diff --git a/Makefile b/Makefile index 85562bbaf..1daa1a503 100644 --- a/Makefile +++ b/Makefile @@ -208,8 +208,8 @@ COMMON_FLAGS ?= ${VERIFY_FLAG} --go-header-file $(shell pwd)/hack/boilerplate.go .PHONY: manifests manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. $(CONTROLLER_GEN) crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases - $(CONTROLLER_GEN) rbac:roleName=agent-role paths="./controllers/bpfman-agent/..." output:rbac:artifacts:config=config/rbac/bpfman-agent - $(CONTROLLER_GEN) rbac:roleName=operator-role paths="./controllers/bpfman-operator" output:rbac:artifacts:config=config/rbac/bpfman-operator + $(CONTROLLER_GEN) rbac:roleName=agent-role paths="./controllers/bpfman-agent/...;./controllers/app-agent/..." output:rbac:artifacts:config=config/rbac/bpfman-agent + $(CONTROLLER_GEN) rbac:roleName=operator-role paths="./controllers/bpfman-operator;./controllers/app-operator" output:rbac:artifacts:config=config/rbac/bpfman-operator .PHONY: generate generate: manifests generate-register generate-deepcopy generate-typed-clients generate-typed-listers generate-typed-informers ## Generate ALL auto-generated code. diff --git a/PROJECT b/PROJECT index bf2c35e79..edcdde0f9 100644 --- a/PROJECT +++ b/PROJECT @@ -129,4 +129,11 @@ resources: kind: BpfNsApplication path: github.com/bpfman/bpfman-operator/apis/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + controller: true + domain: bpfman.io + kind: BpfApplicationState + path: github.com/bpfman/bpfman-operator/apis/v1alpha1 + version: v1alpha1 version: "3" diff --git a/TODO.md b/TODO.md new file mode 100644 index 000000000..afb57a35b --- /dev/null +++ b/TODO.md @@ -0,0 +1,155 @@ +# Intro + +The code has support for XDP, TCX, and Fentry programs in a BpfApplication. + +It's written so that Dave's load/attach split code should drop in pretty easily, +but it's not using it yet. I'm simulating the attachments by reloading the code +for each attachment (like we do today). + +# Observation/Question +Fentry and Fexit programs break the mold. + +Fentry and Fexit programs need to be loaded separately for each attach point, so +the user must specify the BPF function name and attach point together for each +attachment. The user can then attach or detach that program later, but if the +user wants to attach the same Fentry/Fexit program to a different attach point, +the program must be loaded again with the new attach point. + +For other program types, the user can load a program, and then attach or detach +the program to/from multiple attach points at any time after it has been loaded. + +Some differences that result from these requirements: +- Each Fentry/Fexit attach point results in a unique bpf program ID (even if + they all use the same bpf function) +- For other types, a given bpf program can have one bpf program ID (assigned + when it's loaded), plus multiple attach IDs (assigened when it is attached) +- We don't need an attach ID for Fentry/Fexit programs. + +We need to do one of the following: +- Not support the user modifying Fentry/Fexit attach points after the initial + BpfApplication load. +- Load the program if they add an attach point (which would result in an + independent set of global data), and unload the program if they remove an + attachment. + +Yaml options: + +**Option 1:** The current design uses a map indexed by the bpffunction name, so +we can only list a given bpffunction name once followed by a list of attach +points as shown below. This represents Fentry/Fexit programs the same way as +others, but they would need to behave differently as outlined above. + +```yaml +programs: + tcx_stats: + type: TCX + tcx: + attach_points: + - interfaceselector: + primarynodeinterface: true + priority: 500 + direction: ingress + - interfaceselector: + interfaces: + - eth1 + priority: 100 + direction: egress + test_fentry: + type: Fentry + fentry: + attach_points: + - function_name: do_unlinkat + attach: true + - function_name: tcp_connect + attach: false +``` + +**Options 2:** Use a slice, and allow the same Fentry/Fexit functions to be +included multiple times. The is more like the bpfman api, but potentially more +cumbersome for Fentry/Fexit programs. + +```yaml + programs: + - type: TCX + tcx: + bpffunctionname: tcx_stats + attach_points: + - interfaceselector: + primarynodeinterface: true + priority: 500 + direction: ingress + - interfaceselector: + interfaces: + - eth0 + priority: 100 + direction: egress + containers: + namespace: bpfman + pods: + matchLabels: + name: bpfman-daemon + containernames: + - bpfman + - bpfman-agent + - type: Fentry + fentry: + bpffunctionname: tcx_stats + function_name: do_unlinkat + attach: true + - type: Fentry + fentry: + bpffunctionname: tcx_stats + function_name: tcp_connect + attach: true +``` + +# New Code + +The new code is mainly in these directories: + +## Updated & working APIs: + +- apis/v1alpha1/fentryProgram_types.go +- apis/v1alpha1/xdpProgram_types.go +- apis/v1alpha1/tcxProgram_types.go +- apis/v1alpha1/bpfApplication_types.go +- apis/v1alpha1/bpfApplicationState_types.go + +Note: the rest are partially updated. + +## New Agent: + +- controllers/app-agent + +## New Operator: + +- controllers/app-operator + +Note: I left the old bpfman-agent and bpfman-operator code unchanged (except as +needed due to CRD changed). It should work, but it's not being initialized when +we run the operator. + +# Testing: + +- Unit tests for the agent and the operator +- The following working samples: + - config/samples/bpfman.io_v1alpha1_bpfapplication.yaml (XDP & TCX) + - config/samples/bpfman.io_v1alpha1_fentry_bpfapplication.yaml (Fentry) + +# TODO: + +(In no particular order.) + +- Implement Fentry/Fexit solution. +- Integrate with the new bpfman code with load/attach split (of course) +- Create a bpf.o file with all the application types for both cluster and + namespace scoped BpfApplicaitons. +- Redo the status/condition values. I’m currently using the existing framework + and some values for status/conditions, but I intend to create a new set of + conditions/status values that make more sense for the new design. +- Review all comments and logs. +- Maybe make more code common. +- Support the rest of the program types (including namespace-scoped CRDs). +- Delete old directories. +- Lots more testing and code cleanup. +- Lots of other stuff (I'm sure). diff --git a/apis/v1alpha1/bpfApplicationState_types.go b/apis/v1alpha1/bpfApplicationState_types.go new file mode 100644 index 000000000..111f3515c --- /dev/null +++ b/apis/v1alpha1/bpfApplicationState_types.go @@ -0,0 +1,167 @@ +/* +Copyright 2023 The bpfman Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1types "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// BpfApplicationProgramState defines the desired state of BpfApplication +// +union +// +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'XDP' ? has(self.xdp) : !has(self.xdp)",message="xdp configuration is required when type is XDP, and forbidden otherwise" +// // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'TC' ? has(self.tc) : !has(self.tc)",message="tc configuration is required when type is TC, and forbidden otherwise" +// +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'TCX' ? has(self.tcx) : !has(self.tcx)",message="tcx configuration is required when type is TCX, and forbidden otherwise" +// +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Fentry' ? has(self.fentry) : !has(self.fentry)",message="fentry configuration is required when type is Fentry, and forbidden otherwise" +// // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Fexit' ? has(self.fexit) : !has(self.fexit)",message="fexit configuration is required when type is Fexit, and forbidden otherwise" +// // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Kprobe' ? has(self.kprobe) : !has(self.kprobe)",message="kprobe configuration is required when type is Kprobe, and forbidden otherwise" +// // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Kretprobe' ? has(self.kretprobe) : !has(self.kretprobe)",message="kretprobe configuration is required when type is Kretprobe, and forbidden otherwise" +// // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Uprobe' ? has(self.uprobe) : !has(self.uprobe)",message="uprobe configuration is required when type is Uprobe, and forbidden otherwise" +// // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Uretprobe' ? has(self.uretprobe) : !has(self.uretprobe)",message="uretprobe configuration is required when type is Uretprobe, and forbidden otherwise" +// // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Tracepoint' ? has(self.tracepoint) : !has(self.tracepoint)",message="tracepoint configuration is required when type is Tracepoint, and forbidden otherwise" +type BpfApplicationProgramState struct { + BpfProgramStateCommon `json:",inline"` + // Type specifies the bpf program type + // +unionDiscriminator + // +kubebuilder:validation:Required + // +kubebuilder:validation:Enum:="XDP";"TC";"TCX";"Fentry";"Fexit";"Kprobe";"Kretprobe";"Uprobe";"Uretprobe";"Tracepoint" + Type EBPFProgType `json:"type,omitempty"` + + // xdp defines the desired state of the application's XdpPrograms. + // +unionMember + // +optional + XDP *XdpProgramInfoState `json:"xdp,omitempty"` + + // tc defines the desired state of the application's TcPrograms. + // +unionMember + // +optional + TC *TcProgramInfoState `json:"tc,omitempty"` + + // tcx defines the desired state of the application's TcxPrograms. + // +unionMember + // +optional + TCX *TcxProgramInfoState `json:"tcx,omitempty"` + + // fentry defines the desired state of the application's FentryPrograms. + // +unionMember + // +optional + Fentry *FentryProgramInfoState `json:"fentry,omitempty"` + + // // fexit defines the desired state of the application's FexitPrograms. + // // +unionMember + // // +optional + // Fexit *FexitProgramInfoState `json:"fexit,omitempty"` + + // // kprobe defines the desired state of the application's KprobePrograms. + // // +unionMember + // // +optional + // Kprobe *KprobeProgramInfoState `json:"kprobe,omitempty"` + + // // kretprobe defines the desired state of the application's KretprobePrograms. + // // +unionMember + // // +optional + // Kretprobe *KprobeProgramInfoState `json:"kretprobe,omitempty"` + + // // uprobe defines the desired state of the application's UprobePrograms. + // // +unionMember + // // +optional + // Uprobe *UprobeProgramInfoState `json:"uprobe,omitempty"` + + // // uretprobe defines the desired state of the application's UretprobePrograms. + // // +unionMember + // // +optional + // Uretprobe *UprobeProgramInfoState `json:"uretprobe,omitempty"` + + // // tracepoint defines the desired state of the application's TracepointPrograms. + // // +unionMember + // // +optional + // Tracepoint *TracepointProgramInfoState `json:"tracepoint,omitempty"` +} + +// BpfApplicationSpec defines the desired state of BpfApplication +type BpfApplicationStateSpec struct { + // Node is the name of the node for this BpfApplicationStateSpec. + Node string `json:"node"` + // The number of times the BpfApplicationState has been updated. Set to 1 + // when the object is created, then it is incremented prior to each update. + // This allows us to verify that the API server has the updated object prior + // to starting a new Reconcile operation. + UpdateCount int64 `json:"updatecount"` + // AppLoadStatus reflects the status of loading the bpf application on the + // given node. + AppLoadStatus BpfProgramConditionType `json:"apploadstatus"` + // Programs is a list of bpf programs contained in the parent application. + // It is a map from the bpf program name to BpfApplicationProgramState + // elements. + Programs []BpfApplicationProgramState `json:"programs,omitempty"` +} + +// +genclient +// +genclient:nonNamespaced +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// BpfApplicationState contains the per-node state of a BpfApplication. +// ANF-TODO: I can't get the Node to display in the kubectl output. +// +kubebuilder:printcolumn:name="Node",type=string,JSONPath=".spec.node" +// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[0].reason` +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +type BpfApplicationState struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec BpfApplicationStateSpec `json:"spec,omitempty"` + Status BpfAppStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +// BpfApplicationStateList contains a list of BpfApplicationState objects +type BpfApplicationStateList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []BpfApplicationState `json:"items"` +} + +func (an BpfApplicationState) GetName() string { + return an.Name +} + +func (an BpfApplicationState) GetUID() metav1types.UID { + return an.UID +} + +func (an BpfApplicationState) GetAnnotations() map[string]string { + return an.Annotations +} + +func (an BpfApplicationState) GetLabels() map[string]string { + return an.Labels +} + +func (an BpfApplicationState) GetStatus() *BpfAppStatus { + return &an.Status +} + +func (an BpfApplicationState) GetClientObject() client.Object { + return &an +} + +func (anl BpfApplicationStateList) GetItems() []BpfApplicationState { + return anl.Items +} diff --git a/apis/v1alpha1/bpfApplication_types.go b/apis/v1alpha1/bpfApplication_types.go index 47360ca0c..1091ae0dd 100644 --- a/apis/v1alpha1/bpfApplication_types.go +++ b/apis/v1alpha1/bpfApplication_types.go @@ -68,6 +68,7 @@ const ( // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Uretprobe' ? has(self.uretprobe) : !has(self.uretprobe)",message="uretprobe configuration is required when type is Uretprobe, and forbidden otherwise" // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Tracepoint' ? has(self.tracepoint) : !has(self.tracepoint)",message="tracepoint configuration is required when type is Tracepoint, and forbidden otherwise" type BpfApplicationProgram struct { + BpfProgramCommon `json:",inline"` // Type specifies the bpf program type // +unionDiscriminator // +kubebuilder:validation:Required @@ -128,19 +129,12 @@ type BpfApplicationProgram struct { // BpfApplicationSpec defines the desired state of BpfApplication type BpfApplicationSpec struct { BpfAppCommon `json:",inline"` - - // Programs is a list of bpf programs supported for a specific application. - // It's possible that the application can selectively choose which program(s) - // to run from this list. - // +kubebuilder:validation:MinItems:=1 + // Programs is the list of bpf programs in the BpfApplication that should be + // loaded. The application can selectively choose which program(s) to run + // from this list based on the optional attach points provided. Programs []BpfApplicationProgram `json:"programs,omitempty"` } -// BpfApplicationStatus defines the observed state of BpfApplication -type BpfApplicationStatus struct { - BpfProgramStatusCommon `json:",inline"` -} - // +genclient // +genclient:nonNamespaced //+kubebuilder:object:root=true @@ -155,8 +149,8 @@ type BpfApplication struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec BpfApplicationSpec `json:"spec,omitempty"` - Status BpfApplicationStatus `json:"status,omitempty"` + Spec BpfApplicationSpec `json:"spec,omitempty"` + Status BpfAppStatus `json:"status,omitempty"` } // +kubebuilder:object:root=true diff --git a/apis/v1alpha1/bpfNsApplication_types.go b/apis/v1alpha1/bpfNsApplication_types.go index acd78ba79..0d01a4bb1 100644 --- a/apis/v1alpha1/bpfNsApplication_types.go +++ b/apis/v1alpha1/bpfNsApplication_types.go @@ -85,7 +85,7 @@ type BpfNsApplication struct { metav1.ObjectMeta `json:"metadata,omitempty"` Spec BpfNsApplicationSpec `json:"spec,omitempty"` - Status BpfApplicationStatus `json:"status,omitempty"` + Status BpfAppStatus `json:"status,omitempty"` } // +kubebuilder:object:root=true diff --git a/apis/v1alpha1/fentryProgram_types.go b/apis/v1alpha1/fentryProgram_types.go index 4b82fdb43..8e6740515 100644 --- a/apis/v1alpha1/fentryProgram_types.go +++ b/apis/v1alpha1/fentryProgram_types.go @@ -37,9 +37,8 @@ type FentryProgram struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec FentryProgramSpec `json:"spec"` - // +optional - Status FentryProgramStatus `json:"status,omitempty"` + Spec FentryProgramSpec `json:"spec"` + Status BpfAppStatus `json:"status,omitempty"` } // FentryProgramSpec defines the desired state of FentryProgram @@ -52,13 +51,23 @@ type FentryProgramSpec struct { // FentryProgramInfo defines the Fentry program details type FentryProgramInfo struct { BpfProgramCommon `json:",inline"` - // Function to attach the fentry to. - FunctionName string `json:"func_name"` + FentryLoadInfo `json:",inline"` + // Whether the program should be attached to the function. + // This may be updated after the program has been loaded. + // +optional + FentryAttachInfo `json:",inline"` +} + +// FentryLoadInfo contains the program-specific load information for Fentry +// programs +type FentryLoadInfo struct { + // FunctionName is the name of the function to attach the Fentry program to. + FunctionName string `json:"function_name"` } -// FentryProgramStatus defines the observed state of FentryProgram -type FentryProgramStatus struct { - BpfProgramStatusCommon `json:",inline"` +type FentryAttachInfo struct { + // Whether the bpf program should be attached to the function. + Attach bool `json:"attach"` } // +kubebuilder:object:root=true @@ -68,3 +77,14 @@ type FentryProgramList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []FentryProgram `json:"items"` } + +type FentryProgramInfoState struct { + BpfProgramStateCommon `json:",inline"` + FentryLoadInfo `json:",inline"` + FentryAttachInfoState `json:",inline"` +} + +type FentryAttachInfoState struct { + AttachInfoCommon `json:",inline"` + Attach bool `json:"attach"` +} diff --git a/apis/v1alpha1/fexitProgram_types.go b/apis/v1alpha1/fexitProgram_types.go index 97467996e..87d0f5a29 100644 --- a/apis/v1alpha1/fexitProgram_types.go +++ b/apis/v1alpha1/fexitProgram_types.go @@ -37,9 +37,8 @@ type FexitProgram struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec FexitProgramSpec `json:"spec"` - // +optional - Status FexitProgramStatus `json:"status,omitempty"` + Spec FexitProgramSpec `json:"spec"` + Status BpfAppStatus `json:"status,omitempty"` } // FexitProgramSpec defines the desired state of FexitProgram @@ -52,13 +51,22 @@ type FexitProgramSpec struct { // FexitProgramInfo defines the Fexit program details type FexitProgramInfo struct { BpfProgramCommon `json:",inline"` - // Function to attach the fexit to. - FunctionName string `json:"func_name"` + FexitLoadInfo `json:",inline"` + // Whether the program should be attached to the function. + // This may be updated after the program has been loaded. + // +optional + FexitAttachInfo `json:",inline"` +} + +// FexitLoadInfo contains the program-specific load information for Fexit +// programs +type FexitLoadInfo struct { + // FunctionName is the name of the function to attach the Fexit program to. + FunctionName string `json:"function_name"` } -// FexitProgramStatus defines the observed state of FexitProgram -type FexitProgramStatus struct { - BpfProgramStatusCommon `json:",inline"` +type FexitAttachInfo struct { + Attach bool `json:"attach"` } // +kubebuilder:object:root=true diff --git a/apis/v1alpha1/kprobeProgram_types.go b/apis/v1alpha1/kprobeProgram_types.go index 796a81da7..d53b202e0 100644 --- a/apis/v1alpha1/kprobeProgram_types.go +++ b/apis/v1alpha1/kprobeProgram_types.go @@ -39,16 +39,14 @@ type KprobeProgram struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec KprobeProgramSpec `json:"spec"` - // +optional - Status KprobeProgramStatus `json:"status,omitempty"` + Spec KprobeProgramSpec `json:"spec"` + Status BpfAppStatus `json:"status,omitempty"` } // KprobeProgramSpec defines the desired state of KprobeProgram // +kubebuilder:printcolumn:name="FunctionName",type=string,JSONPath=`.spec.func_name` // +kubebuilder:printcolumn:name="Offset",type=integer,JSONPath=`.spec.offset` // +kubebuilder:printcolumn:name="RetProbe",type=boolean,JSONPath=`.spec.retprobe` -// +kubebuilder:validation:XValidation:message="offset cannot be set for kretprobes",rule="self.retprobe == false || self.offset == 0" type KprobeProgramSpec struct { KprobeProgramInfo `json:",inline"` BpfAppCommon `json:",inline"` @@ -57,7 +55,14 @@ type KprobeProgramSpec struct { // KprobeProgramInfo defines the common fields for KprobeProgram type KprobeProgramInfo struct { BpfProgramCommon `json:",inline"` + // The list of points to which the program should be attached. The list is + // optional and may be udated after the bpf program has been loaded + // +optional + AttachPoints []KprobeAttachInfo `json:"attach_points"` +} +// +kubebuilder:validation:XValidation:message="offset cannot be set for kretprobes",rule="self.retprobe == false || self.offset == 0" +type KprobeAttachInfo struct { // Functions to attach the kprobe to. FunctionName string `json:"func_name"` @@ -73,11 +78,6 @@ type KprobeProgramInfo struct { RetProbe bool `json:"retprobe"` } -// KprobeProgramStatus defines the observed state of KprobeProgram -type KprobeProgramStatus struct { - BpfProgramStatusCommon `json:",inline"` -} - // +kubebuilder:object:root=true // KprobeProgramList contains a list of KprobePrograms type KprobeProgramList struct { diff --git a/apis/v1alpha1/shared_types.go b/apis/v1alpha1/shared_types.go index 7a6dca35f..43a573501 100644 --- a/apis/v1alpha1/shared_types.go +++ b/apis/v1alpha1/shared_types.go @@ -67,18 +67,23 @@ type ContainerNsSelector struct { ContainerNames *[]string `json:"containernames,omitempty"` } +// ANF-TODO: When we get rid of the old programs, we can remove this from the +// individual *ProgramInfo structs. // BpfProgramCommon defines the common attributes for all BPF programs type BpfProgramCommon struct { // BpfFunctionName is the name of the function that is the entry point for the BPF // program BpfFunctionName string `json:"bpffunctionname"` - // MapOwnerSelector is used to select the loaded eBPF program this eBPF program - // will share a map with. The value is a label applied to the BpfProgram to select. - // The selector must resolve to exactly one instance of a BpfProgram on a given node - // or the eBPF program will not load. + // ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + // new load/attach split code. + // + // OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + // program will share a map with. The value is a label applied to the + // BpfProgram to select. The selector must resolve to exactly one instance + // of a BpfProgram on a given node or the eBPF program will not load. // +optional - MapOwnerSelector metav1.LabelSelector `json:"mapownerselector"` + OldMapOwnerSelector metav1.LabelSelector `json:"oldmapownerselector"` } // BpfAppCommon defines the common attributes for all BpfApp programs @@ -98,12 +103,23 @@ type BpfAppCommon struct { // Bytecode configures where the bpf program's bytecode should be loaded // from. ByteCode BytecodeSelector `json:"bytecode"` + + // ANF-TODO: Update code so that it pulls MapOwnerSelector from BpfAppCommon + // instead of AppProgramCommon. + + // MapOwnerSelector is used to select the loaded eBPF program this eBPF program + // will share a map with. The value is a label applied to the BpfProgram to select. + // The selector must resolve to exactly one instance of a BpfProgram on a given node + // or the eBPF program will not load. + // +optional + MapOwnerSelector *metav1.LabelSelector `json:"mapownerselector"` } -// BpfProgramStatusCommon defines the BpfProgram status -type BpfProgramStatusCommon struct { - // Conditions houses the global cluster state for the eBPFProgram. The explicit - // condition types are defined internally. +// BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState object +type BpfAppStatus struct { + // For a BpfApplication object, Conditions contains the global cluster state + // for the object. For a BpfApplicationState object, Conditions contains the + // state of the BpfApplication object on the given node. // +patchMergeKey=type // +patchStrategy=merge // +listType=map @@ -111,6 +127,35 @@ type BpfProgramStatusCommon struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"` } +// AttachInfoCommon reflects the status for one attach point for a given bpf +// application program +type AttachInfoCommon struct { + // ShouldAttach reflects whether the attachment should exist. + ShouldAttach bool `json:"should_attach"` + // ANF-TODO: Putting a uuid here for now to maintain compatibility with the + // existing BpfProgram. + UUID string `json:"uuid"` + // An identifier for the attach point assigned by bpfman. This field is + // empty until the program is successfully attached and bpfman returns the + // id. + // ANF-TODO: For the POC, this will be the program ID. + AttachId *uint32 `json:"attachid"` + // AttachStatus reflects whether the attachment has been reconciled + // successfully, and if not, why. + AttachStatus BpfProgramConditionType `json:"attachstatus"` +} + +type BpfProgramStateCommon struct { + BpfProgramCommon `json:",inline"` + // ProgramAttachStatus records whether the program should be loaded and whether + // the program is loaded. + ProgramAttachStatus BpfProgramConditionType `json:"programattachstatus"` + // ProgramId is the id of the program in the kernel. Not set until the + // program is loaded. + // +optional + ProgramId *uint32 `json:"program_id"` +} + // PullPolicy describes a policy for if/when to pull a container image // +kubebuilder:validation:Enum=Always;Never;IfNotPresent type PullPolicy string @@ -293,6 +338,22 @@ const ( // that match the container selector. BpfProgCondNoContainersOnNode BpfProgramConditionType = "NoContainersOnNode" + // BpfProgCondAttached indicates that the attachment is attached. Whether + // this is good depends on whether it should be attached. + BpfProgCondAttached BpfProgramConditionType = "Attached" + + // BpfProgCondNotAttached indicates that the attachment is not attached. + // Whether this is good depends on whether it should be attached. + BpfProgCondNotAttached BpfProgramConditionType = "NotAttached" + + // BpfProgCondAttachSuccess indicates that all attachments for a given bpf + // program were successful. + BpfProgCondAttachSuccess BpfProgramConditionType = "AttachSuccess" + + // BpfProgCondError indicates that one or more attachments for a given bpf + // program was not successful. + BpfProgCondAttachError BpfProgramConditionType = "AttachError" + // None of the above conditions apply BpfProgCondNone BpfProgramConditionType = "None" ) @@ -369,6 +430,38 @@ func (b BpfProgramConditionType) Condition() metav1.Condition { Message: "There are no containers on the node that match the container selector", } + case BpfProgCondAttached: + cond = metav1.Condition{ + Type: string(BpfProgCondAttached), + Status: metav1.ConditionTrue, + Reason: "attached", + Message: "Attachment is currently active", + } + + case BpfProgCondNotAttached: + cond = metav1.Condition{ + Type: string(BpfProgCondNotAttached), + Status: metav1.ConditionTrue, + Reason: "notAttached", + Message: "Attachment is currently not active", + } + + case BpfProgCondAttachSuccess: + cond = metav1.Condition{ + Type: string(BpfProgCondAttachSuccess), + Status: metav1.ConditionTrue, + Reason: "attachFailed", + Message: "All attachments were successful", + } + + case BpfProgCondAttachError: + cond = metav1.Condition{ + Type: string(BpfProgCondAttachError), + Status: metav1.ConditionTrue, + Reason: "attachFailed", + Message: "One or more attachments were not successful", + } + case BpfProgCondNone: cond = metav1.Condition{ Type: string(BpfProgCondNone), diff --git a/apis/v1alpha1/tcNsProgram_types.go b/apis/v1alpha1/tcNsProgram_types.go index a8eca7372..6745d2e1a 100644 --- a/apis/v1alpha1/tcNsProgram_types.go +++ b/apis/v1alpha1/tcNsProgram_types.go @@ -41,7 +41,7 @@ type TcNsProgram struct { Spec TcNsProgramSpec `json:"spec"` // +optional - Status TcProgramStatus `json:"status,omitempty"` + Status BpfAppStatus `json:"status,omitempty"` } // TcNsProgramSpec defines the desired state of TcNsProgram @@ -50,10 +50,16 @@ type TcNsProgramSpec struct { BpfAppCommon `json:",inline"` } -// TcNsProgramInfo defines the tc program details +// TcProgramInfo defines the tc program details type TcNsProgramInfo struct { BpfProgramCommon `json:",inline"` + // The list of points to which the program should be attached. The list is + // optional and may be udated after the bpf program has been loaded + // +optional + AttachPoints []TcNsAttachInfo `json:"attach_points"` +} +type TcNsAttachInfo struct { // Selector to determine the network interface (or interfaces) InterfaceSelector InterfaceSelector `json:"interfaceselector"` diff --git a/apis/v1alpha1/tcProgram_types.go b/apis/v1alpha1/tcProgram_types.go index 519234214..7d3f00926 100644 --- a/apis/v1alpha1/tcProgram_types.go +++ b/apis/v1alpha1/tcProgram_types.go @@ -40,9 +40,8 @@ type TcProgram struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec TcProgramSpec `json:"spec"` - // +optional - Status TcProgramStatus `json:"status,omitempty"` + Spec TcProgramSpec `json:"spec"` + Status BpfAppStatus `json:"status,omitempty"` } // +kubebuilder:validation:Enum=unspec;ok;reclassify;shot;pipe;stolen;queued;repeat;redirect;trap;dispatcher_return @@ -57,7 +56,13 @@ type TcProgramSpec struct { // TcProgramInfo defines the tc program details type TcProgramInfo struct { BpfProgramCommon `json:",inline"` + // The list of points to which the program should be attached. The list is + // optional and may be udated after the bpf program has been loaded + // +optional + AttachPoints []TcAttachInfo `json:"attach_points"` +} +type TcAttachInfo struct { // Selector to determine the network interface (or interfaces) InterfaceSelector InterfaceSelector `json:"interfaceselector"` @@ -87,11 +92,6 @@ type TcProgramInfo struct { ProceedOn []TcProceedOnValue `json:"proceedon"` } -// TcProgramStatus defines the observed state of TcProgram -type TcProgramStatus struct { - BpfProgramStatusCommon `json:",inline"` -} - // +kubebuilder:object:root=true // TcProgramList contains a list of TcPrograms type TcProgramList struct { @@ -99,3 +99,45 @@ type TcProgramList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []TcProgram `json:"items"` } + +type TcProgramInfoState struct { + // The list of points to which the program should be attached. + // TcAttachInfoState is similar to TcAttachInfo, but the interface and + // container selectors are expanded, and we have one instance of + // TcAttachInfoState for each unique attach point. The list is optional and + // may be udated after the bpf program has been loaded. + // +optional + AttachPoints []TcAttachInfoState `json:"attach_points"` +} + +type TcAttachInfoState struct { + AttachInfoCommon `json:",inline"` + // An identifier for the attach point assigned by bpfman. This field is + // empty until the program is successfully attached and bpfman returns the + // id. + AttachId *uint32 `json:"attachid"` + + // Interface name to attach the tc program to. + IfName string `json:"ifname"` + + // Optional container pid to attach the tc program in. + // +optional + ContainerPid *uint32 `json:"containerpid"` + + // Priority specifies the priority of the tc program in relation to + // other programs of the same type with the same attach point. It is a value + // from 0 to 1000 where lower values have higher precedence. + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=1000 + Priority int32 `json:"priority"` + + // Direction specifies the direction of traffic the tc program should + // attach to for a given network device. + // +kubebuilder:validation:Enum=ingress;egress + Direction string `json:"direction"` + + // ProceedOn allows the user to call other tc programs in chain on this exit code. + // Multiple values are supported by repeating the parameter. + // +kubebuilder:validation:MaxItems=11 + ProceedOn []TcProceedOnValue `json:"proceedon"` +} diff --git a/apis/v1alpha1/tcxNsProgram_types.go b/apis/v1alpha1/tcxNsProgram_types.go index 61b8c8df3..5e721373b 100644 --- a/apis/v1alpha1/tcxNsProgram_types.go +++ b/apis/v1alpha1/tcxNsProgram_types.go @@ -41,7 +41,7 @@ type TcxNsProgram struct { Spec TcxNsProgramSpec `json:"spec"` // +optional - Status TcxProgramStatus `json:"status,omitempty"` + Status BpfAppStatus `json:"status,omitempty"` } // TcxNsProgramSpec defines the desired state of TcxNsProgram @@ -53,12 +53,19 @@ type TcxNsProgramSpec struct { // TcxNsProgramInfo defines the TCX Ns Program details type TcxNsProgramInfo struct { BpfProgramCommon `json:",inline"` + // The list of points to which the program should be attached. The list is + // optional and may be udated after the bpf program has been loaded + // +optional + AttachPoints []TcxNsAttachInfo `json:"attach_points"` +} +type TcxNsAttachInfo struct { // Selector to determine the network interface (or interfaces) InterfaceSelector InterfaceSelector `json:"interfaceselector"` // Containers identifies the set of containers in which to attach the eBPF - // program. + // program. If Containers is not specified, the BPF program will be attached + // in the root network namespace. Containers ContainerNsSelector `json:"containers"` // Direction specifies the direction of traffic the tcx program should diff --git a/apis/v1alpha1/tcxProgram_types.go b/apis/v1alpha1/tcxProgram_types.go index e3de33c87..31d632686 100644 --- a/apis/v1alpha1/tcxProgram_types.go +++ b/apis/v1alpha1/tcxProgram_types.go @@ -32,17 +32,17 @@ import ( // +kubebuilder:printcolumn:name="BpfFunctionName",type=string,JSONPath=`.spec.bpffunctionname` // +kubebuilder:printcolumn:name="NodeSelector",type=string,JSONPath=`.spec.nodeselector` // +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[0].reason` +// +kubebuilder:printcolumn:name="Priority",type=string,JSONPath=`.spec.priority`,priority=1 // +kubebuilder:printcolumn:name="Direction",type=string,JSONPath=`.spec.direction`,priority=1 // +kubebuilder:printcolumn:name="InterfaceSelector",type=string,JSONPath=`.spec.interfaceselector`,priority=1 // +kubebuilder:printcolumn:name="Position",type=string,JSONPath=`.spec.position`,priority=1 -// +kubebuilder:printcolumn:name="Priority",type=string,JSONPath=`.spec.priority`,priority=1 type TcxProgram struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` Spec TcxProgramSpec `json:"spec"` // +optional - Status TcxProgramStatus `json:"status,omitempty"` + Status BpfAppStatus `json:"status,omitempty"` } // TcxProgramSpec defines the desired state of TcxProgram @@ -51,10 +51,16 @@ type TcxProgramSpec struct { BpfAppCommon `json:",inline"` } -// TcxProgramInfo defines the tc program details +// TcxProgramInfo defines the tcx program details type TcxProgramInfo struct { BpfProgramCommon `json:",inline"` + // The list of points to which the program should be attached. The list is + // optional and may be udated after the bpf program has been loaded + // +optional + AttachPoints []TcxAttachInfo `json:"attach_points"` +} +type TcxAttachInfo struct { // Selector to determine the network interface (or interfaces) InterfaceSelector InterfaceSelector `json:"interfaceselector"` @@ -69,7 +75,7 @@ type TcxProgramInfo struct { // +kubebuilder:validation:Enum=ingress;egress Direction string `json:"direction"` - // Priority specifies the priority of the tc program in relation to + // Priority specifies the priority of the tcx program in relation to // other programs of the same type with the same attach point. It is a value // from 0 to 1000 where lower values have higher precedence. // +kubebuilder:validation:Minimum=0 @@ -77,11 +83,6 @@ type TcxProgramInfo struct { Priority int32 `json:"priority"` } -// TcxProgramStatus defines the observed state of TcxProgram -type TcxProgramStatus struct { - BpfProgramStatusCommon `json:",inline"` -} - // +kubebuilder:object:root=true // TcxProgramList contains a list of TcxPrograms type TcxProgramList struct { @@ -89,3 +90,36 @@ type TcxProgramList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []TcxProgram `json:"items"` } + +type TcxProgramInfoState struct { + // The list of points to which the program should be attached. + // TcxAttachInfoState is similar to TcxAttachInfo, but the interface and + // container selectors are expanded, and we have one instance of + // TcxAttachInfoState for each unique attach point. The list is optional and + // may be udated after the bpf program has been loaded. + // +optional + AttachPoints []TcxAttachInfoState `json:"attach_points"` +} + +type TcxAttachInfoState struct { + AttachInfoCommon `json:",inline"` + + // Interface name to attach the tcx program to. + IfName string `json:"ifname"` + + // Optional container pid to attach the tcx program in. + // +optional + ContainerPid *uint32 `json:"containerpid"` + + // Direction specifies the direction of traffic the tcx program should + // attach to for a given network device. + // +kubebuilder:validation:Enum=ingress;egress + Direction string `json:"direction"` + + // Priority specifies the priority of the tcx program in relation to + // other programs of the same type with the same attach point. It is a value + // from 0 to 1000 where lower values have higher precedence. + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=1000 + Priority int32 `json:"priority"` +} diff --git a/apis/v1alpha1/tracepointProgram_types.go b/apis/v1alpha1/tracepointProgram_types.go index e692192a8..48ddc1e47 100644 --- a/apis/v1alpha1/tracepointProgram_types.go +++ b/apis/v1alpha1/tracepointProgram_types.go @@ -37,9 +37,8 @@ type TracepointProgram struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec TracepointProgramSpec `json:"spec"` - // +optional - Status TracepointProgramStatus `json:"status,omitempty"` + Spec TracepointProgramSpec `json:"spec"` + Status BpfAppStatus `json:"status,omitempty"` } // TracepointProgramSpec defines the desired state of TracepointProgram @@ -52,15 +51,16 @@ type TracepointProgramSpec struct { // TracepointProgramInfo defines the Tracepoint program details type TracepointProgramInfo struct { BpfProgramCommon `json:",inline"` - - // Names refers to the names of kernel tracepoints to attach the - // bpf program to. - Names []string `json:"names"` + // The list of points to which the program should be attached. The list is + // optional and may be udated after the bpf program has been loaded + // +optional + AttachPoints []TracepointAttachInfo `json:"attach_points"` } -// TracepointProgramStatus defines the observed state of TracepointProgram -type TracepointProgramStatus struct { - BpfProgramStatusCommon `json:",inline"` +type TracepointAttachInfo struct { + // Name refers to the name of a kernel tracepoint to attach the + // bpf program to. + Name string `json:"name"` } // +kubebuilder:object:root=true diff --git a/apis/v1alpha1/uprobeNsProgram_types.go b/apis/v1alpha1/uprobeNsProgram_types.go index 2b8dd21e0..ae3f8db28 100644 --- a/apis/v1alpha1/uprobeNsProgram_types.go +++ b/apis/v1alpha1/uprobeNsProgram_types.go @@ -42,7 +42,7 @@ type UprobeNsProgram struct { Spec UprobeNsProgramSpec `json:"spec"` // +optional - Status UprobeProgramStatus `json:"status,omitempty"` + Status BpfAppStatus `json:"status,omitempty"` } // UprobeNsProgramSpec defines the desired state of UprobeProgram @@ -51,10 +51,16 @@ type UprobeNsProgramSpec struct { BpfAppCommon `json:",inline"` } -// UprobeProgramInfo contains the information about the uprobe program +// UprobeNsProgramInfo contains the information about the uprobe program type UprobeNsProgramInfo struct { BpfProgramCommon `json:",inline"` + // The list of points to which the program should be attached. The list is + // optional and may be udated after the bpf program has been loaded + // +optional + AttachPoints []UprobeNsAttachInfo `json:"attach_points"` +} +type UprobeNsAttachInfo struct { // Function to attach the uprobe to. // +optional FunctionName string `json:"func_name"` diff --git a/apis/v1alpha1/uprobeProgram_types.go b/apis/v1alpha1/uprobeProgram_types.go index 664401145..1d4d49144 100644 --- a/apis/v1alpha1/uprobeProgram_types.go +++ b/apis/v1alpha1/uprobeProgram_types.go @@ -41,9 +41,8 @@ type UprobeProgram struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec UprobeProgramSpec `json:"spec"` - // +optional - Status UprobeProgramStatus `json:"status,omitempty"` + Spec UprobeProgramSpec `json:"spec"` + Status BpfAppStatus `json:"status,omitempty"` } // UprobeProgramSpec defines the desired state of UprobeProgram @@ -60,7 +59,13 @@ type UprobeProgramSpec struct { // UprobeProgramInfo contains the information about the uprobe program type UprobeProgramInfo struct { BpfProgramCommon `json:",inline"` + // The list of points to which the program should be attached. The list is + // optional and may be udated after the bpf program has been loaded + // +optional + AttachPoints []UprobeAttachInfo `json:"attach_points"` +} +type UprobeAttachInfo struct { // Function to attach the uprobe to. // +optional FunctionName string `json:"func_name"` @@ -93,11 +98,6 @@ type UprobeProgramInfo struct { Containers *ContainerSelector `json:"containers"` } -// UprobeProgramStatus defines the observed state of UprobeProgram -type UprobeProgramStatus struct { - BpfProgramStatusCommon `json:",inline"` -} - // +kubebuilder:object:root=true // UprobeProgramList contains a list of UprobePrograms type UprobeProgramList struct { diff --git a/apis/v1alpha1/xdpNsProgram_types.go b/apis/v1alpha1/xdpNsProgram_types.go index d0619c074..f1fed22bd 100644 --- a/apis/v1alpha1/xdpNsProgram_types.go +++ b/apis/v1alpha1/xdpNsProgram_types.go @@ -52,6 +52,13 @@ type XdpNsProgramSpec struct { // XdpNsProgramInfo defines the common fields for all XdpProgram types type XdpNsProgramInfo struct { BpfProgramCommon `json:",inline"` + // The list of points to which the program should be attached. The list is + // optional and may be udated after the bpf program has been loaded + // +optional + AttachPoints []XdpNsAttachInfo `json:"attach_points"` +} + +type XdpNsAttachInfo struct { // Selector to determine the network interface (or interfaces) InterfaceSelector InterfaceSelector `json:"interfaceselector"` diff --git a/apis/v1alpha1/xdpProgram_types.go b/apis/v1alpha1/xdpProgram_types.go index f39c31981..b7e6e0cef 100644 --- a/apis/v1alpha1/xdpProgram_types.go +++ b/apis/v1alpha1/xdpProgram_types.go @@ -34,6 +34,7 @@ import ( // +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[0].reason` // +kubebuilder:printcolumn:name="Priority",type=string,JSONPath=`.spec.priority`,priority=1 // +kubebuilder:printcolumn:name="InterfaceSelector",type=string,JSONPath=`.spec.interfaceselector`,priority=1 +// +kubebuilder:printcolumn:name="Position",type=string,JSONPath=`.spec.position`,priority=1 // +kubebuilder:printcolumn:name="ProceedOn",type=string,JSONPath=`.spec.proceedon`,priority=1 type XdpProgram struct { metav1.TypeMeta `json:",inline"` @@ -41,7 +42,7 @@ type XdpProgram struct { Spec XdpProgramSpec `json:"spec"` // +optional - Status XdpProgramStatus `json:"status,omitempty"` + Status BpfAppStatus `json:"status,omitempty"` } // +kubebuilder:validation:Enum=aborted;drop;pass;tx;redirect;dispatcher_return @@ -53,9 +54,16 @@ type XdpProgramSpec struct { BpfAppCommon `json:",inline"` } -// XdpProgramInfo defines the common fields for all XdpProgram types +// XdpProgramInfo defines the xdp program details type XdpProgramInfo struct { BpfProgramCommon `json:",inline"` + // The list of points to which the program should be attached. The list is + // optional and may be udated after the bpf program has been loaded + // +optional + AttachPoints []XdpAttachInfo `json:"attach_points"` +} + +type XdpAttachInfo struct { // Selector to determine the network interface (or interfaces) InterfaceSelector InterfaceSelector `json:"interfaceselector"` @@ -77,13 +85,12 @@ type XdpProgramInfo struct { // +optional // +kubebuilder:validation:MaxItems=6 // +kubebuilder:default:={pass,dispatcher_return} - ProceedOn []XdpProceedOnValue `json:"proceedon"` } // XdpProgramStatus defines the observed state of XdpProgram type XdpProgramStatus struct { - BpfProgramStatusCommon `json:",inline"` + BpfAppStatus `json:",inline"` } // +kubebuilder:object:root=true @@ -93,3 +100,36 @@ type XdpProgramList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []XdpProgram `json:"items"` } + +type XdpProgramInfoState struct { + // The list of points to which the program should be attached. + // XdpAttachInfoState is similar to XdpAttachInfo, but the interface and + // container selectors are expanded, and we have one instance of + // XdpAttachInfoState for each unique attach point. The list is optional and + // may be udated after the bpf program has been loaded. + // +optional + AttachPoints []XdpAttachInfoState `json:"attach_points"` +} + +type XdpAttachInfoState struct { + AttachInfoCommon `json:",inline"` + + // Interface name to attach the xdp program to. + IfName string `json:"ifname"` + + // Optional container pid to attach the xdp program in. + // +optional + ContainerPid *uint32 `json:"containerpid"` + + // Priority specifies the priority of the xdp program in relation to + // other programs of the same type with the same attach point. It is a value + // from 0 to 1000 where lower values have higher precedence. + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=1000 + Priority int32 `json:"priority"` + + // ProceedOn allows the user to call other xdp programs in chain on this exit code. + // Multiple values are supported by repeating the parameter. + // +kubebuilder:validation:MaxItems=6 + ProceedOn []XdpProceedOnValue `json:"proceedon"` +} diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index 54af5b645..1f2589424 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -25,6 +25,26 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AttachInfoCommon) DeepCopyInto(out *AttachInfoCommon) { + *out = *in + if in.AttachId != nil { + in, out := &in.AttachId, &out.AttachId + *out = new(uint32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AttachInfoCommon. +func (in *AttachInfoCommon) DeepCopy() *AttachInfoCommon { + if in == nil { + return nil + } + out := new(AttachInfoCommon) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BpfAppCommon) DeepCopyInto(out *BpfAppCommon) { *out = *in @@ -46,6 +66,11 @@ func (in *BpfAppCommon) DeepCopyInto(out *BpfAppCommon) { } } in.ByteCode.DeepCopyInto(&out.ByteCode) + if in.MapOwnerSelector != nil { + in, out := &in.MapOwnerSelector, &out.MapOwnerSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfAppCommon. @@ -58,6 +83,28 @@ func (in *BpfAppCommon) DeepCopy() *BpfAppCommon { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BpfAppStatus) DeepCopyInto(out *BpfAppStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfAppStatus. +func (in *BpfAppStatus) DeepCopy() *BpfAppStatus { + if in == nil { + return nil + } + out := new(BpfAppStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BpfApplication) DeepCopyInto(out *BpfApplication) { *out = *in @@ -120,6 +167,7 @@ func (in *BpfApplicationList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BpfApplicationProgram) DeepCopyInto(out *BpfApplicationProgram) { *out = *in + in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) if in.XDP != nil { in, out := &in.XDP, &out.XDP *out = new(XdpProgramInfo) @@ -182,6 +230,42 @@ func (in *BpfApplicationProgram) DeepCopy() *BpfApplicationProgram { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BpfApplicationProgramState) DeepCopyInto(out *BpfApplicationProgramState) { + *out = *in + in.BpfProgramStateCommon.DeepCopyInto(&out.BpfProgramStateCommon) + if in.XDP != nil { + in, out := &in.XDP, &out.XDP + *out = new(XdpProgramInfoState) + (*in).DeepCopyInto(*out) + } + if in.TC != nil { + in, out := &in.TC, &out.TC + *out = new(TcProgramInfoState) + (*in).DeepCopyInto(*out) + } + if in.TCX != nil { + in, out := &in.TCX, &out.TCX + *out = new(TcxProgramInfoState) + (*in).DeepCopyInto(*out) + } + if in.Fentry != nil { + in, out := &in.Fentry, &out.Fentry + *out = new(FentryProgramInfoState) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfApplicationProgramState. +func (in *BpfApplicationProgramState) DeepCopy() *BpfApplicationProgramState { + if in == nil { + return nil + } + out := new(BpfApplicationProgramState) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BpfApplicationSpec) DeepCopyInto(out *BpfApplicationSpec) { *out = *in @@ -206,17 +290,82 @@ func (in *BpfApplicationSpec) DeepCopy() *BpfApplicationSpec { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BpfApplicationStatus) DeepCopyInto(out *BpfApplicationStatus) { +func (in *BpfApplicationState) DeepCopyInto(out *BpfApplicationState) { *out = *in - in.BpfProgramStatusCommon.DeepCopyInto(&out.BpfProgramStatusCommon) + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfApplicationStatus. -func (in *BpfApplicationStatus) DeepCopy() *BpfApplicationStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfApplicationState. +func (in *BpfApplicationState) DeepCopy() *BpfApplicationState { if in == nil { return nil } - out := new(BpfApplicationStatus) + out := new(BpfApplicationState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BpfApplicationState) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BpfApplicationStateList) DeepCopyInto(out *BpfApplicationStateList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]BpfApplicationState, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfApplicationStateList. +func (in *BpfApplicationStateList) DeepCopy() *BpfApplicationStateList { + if in == nil { + return nil + } + out := new(BpfApplicationStateList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BpfApplicationStateList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BpfApplicationStateSpec) DeepCopyInto(out *BpfApplicationStateSpec) { + *out = *in + if in.Programs != nil { + in, out := &in.Programs, &out.Programs + *out = make([]BpfApplicationProgramState, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfApplicationStateSpec. +func (in *BpfApplicationStateSpec) DeepCopy() *BpfApplicationStateSpec { + if in == nil { + return nil + } + out := new(BpfApplicationStateSpec) in.DeepCopyInto(out) return out } @@ -432,7 +581,7 @@ func (in *BpfProgram) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BpfProgramCommon) DeepCopyInto(out *BpfProgramCommon) { *out = *in - in.MapOwnerSelector.DeepCopyInto(&out.MapOwnerSelector) + in.OldMapOwnerSelector.DeepCopyInto(&out.OldMapOwnerSelector) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfProgramCommon. @@ -493,29 +642,28 @@ func (in *BpfProgramSpec) DeepCopy() *BpfProgramSpec { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BpfProgramStatus) DeepCopyInto(out *BpfProgramStatus) { +func (in *BpfProgramStateCommon) DeepCopyInto(out *BpfProgramStateCommon) { *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } + in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) + if in.ProgramId != nil { + in, out := &in.ProgramId, &out.ProgramId + *out = new(uint32) + **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfProgramStatus. -func (in *BpfProgramStatus) DeepCopy() *BpfProgramStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfProgramStateCommon. +func (in *BpfProgramStateCommon) DeepCopy() *BpfProgramStateCommon { if in == nil { return nil } - out := new(BpfProgramStatus) + out := new(BpfProgramStateCommon) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BpfProgramStatusCommon) DeepCopyInto(out *BpfProgramStatusCommon) { +func (in *BpfProgramStatus) DeepCopyInto(out *BpfProgramStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -526,12 +674,12 @@ func (in *BpfProgramStatusCommon) DeepCopyInto(out *BpfProgramStatusCommon) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfProgramStatusCommon. -func (in *BpfProgramStatusCommon) DeepCopy() *BpfProgramStatusCommon { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfProgramStatus. +func (in *BpfProgramStatus) DeepCopy() *BpfProgramStatus { if in == nil { return nil } - out := new(BpfProgramStatusCommon) + out := new(BpfProgramStatus) in.DeepCopyInto(out) return out } @@ -631,6 +779,52 @@ func (in *ContainerSelector) DeepCopy() *ContainerSelector { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FentryAttachInfo) DeepCopyInto(out *FentryAttachInfo) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FentryAttachInfo. +func (in *FentryAttachInfo) DeepCopy() *FentryAttachInfo { + if in == nil { + return nil + } + out := new(FentryAttachInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FentryAttachInfoState) DeepCopyInto(out *FentryAttachInfoState) { + *out = *in + in.AttachInfoCommon.DeepCopyInto(&out.AttachInfoCommon) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FentryAttachInfoState. +func (in *FentryAttachInfoState) DeepCopy() *FentryAttachInfoState { + if in == nil { + return nil + } + out := new(FentryAttachInfoState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FentryLoadInfo) DeepCopyInto(out *FentryLoadInfo) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FentryLoadInfo. +func (in *FentryLoadInfo) DeepCopy() *FentryLoadInfo { + if in == nil { + return nil + } + out := new(FentryLoadInfo) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FentryProgram) DeepCopyInto(out *FentryProgram) { *out = *in @@ -662,6 +856,8 @@ func (in *FentryProgram) DeepCopyObject() runtime.Object { func (in *FentryProgramInfo) DeepCopyInto(out *FentryProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) + out.FentryLoadInfo = in.FentryLoadInfo + out.FentryAttachInfo = in.FentryAttachInfo } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FentryProgramInfo. @@ -674,6 +870,24 @@ func (in *FentryProgramInfo) DeepCopy() *FentryProgramInfo { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FentryProgramInfoState) DeepCopyInto(out *FentryProgramInfoState) { + *out = *in + in.BpfProgramStateCommon.DeepCopyInto(&out.BpfProgramStateCommon) + out.FentryLoadInfo = in.FentryLoadInfo + in.FentryAttachInfoState.DeepCopyInto(&out.FentryAttachInfoState) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FentryProgramInfoState. +func (in *FentryProgramInfoState) DeepCopy() *FentryProgramInfoState { + if in == nil { + return nil + } + out := new(FentryProgramInfoState) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FentryProgramList) DeepCopyInto(out *FentryProgramList) { *out = *in @@ -724,17 +938,31 @@ func (in *FentryProgramSpec) DeepCopy() *FentryProgramSpec { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FentryProgramStatus) DeepCopyInto(out *FentryProgramStatus) { +func (in *FexitAttachInfo) DeepCopyInto(out *FexitAttachInfo) { *out = *in - in.BpfProgramStatusCommon.DeepCopyInto(&out.BpfProgramStatusCommon) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FentryProgramStatus. -func (in *FentryProgramStatus) DeepCopy() *FentryProgramStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FexitAttachInfo. +func (in *FexitAttachInfo) DeepCopy() *FexitAttachInfo { if in == nil { return nil } - out := new(FentryProgramStatus) + out := new(FexitAttachInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FexitLoadInfo) DeepCopyInto(out *FexitLoadInfo) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FexitLoadInfo. +func (in *FexitLoadInfo) DeepCopy() *FexitLoadInfo { + if in == nil { + return nil + } + out := new(FexitLoadInfo) in.DeepCopyInto(out) return out } @@ -770,6 +998,8 @@ func (in *FexitProgram) DeepCopyObject() runtime.Object { func (in *FexitProgramInfo) DeepCopyInto(out *FexitProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) + out.FexitLoadInfo = in.FexitLoadInfo + out.FexitAttachInfo = in.FexitAttachInfo } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FexitProgramInfo. @@ -831,22 +1061,6 @@ func (in *FexitProgramSpec) DeepCopy() *FexitProgramSpec { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FexitProgramStatus) DeepCopyInto(out *FexitProgramStatus) { - *out = *in - in.BpfProgramStatusCommon.DeepCopyInto(&out.BpfProgramStatusCommon) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FexitProgramStatus. -func (in *FexitProgramStatus) DeepCopy() *FexitProgramStatus { - if in == nil { - return nil - } - out := new(FexitProgramStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ImagePullSecretSelector) DeepCopyInto(out *ImagePullSecretSelector) { *out = *in @@ -891,6 +1105,21 @@ func (in *InterfaceSelector) DeepCopy() *InterfaceSelector { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KprobeAttachInfo) DeepCopyInto(out *KprobeAttachInfo) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KprobeAttachInfo. +func (in *KprobeAttachInfo) DeepCopy() *KprobeAttachInfo { + if in == nil { + return nil + } + out := new(KprobeAttachInfo) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KprobeProgram) DeepCopyInto(out *KprobeProgram) { *out = *in @@ -922,6 +1151,11 @@ func (in *KprobeProgram) DeepCopyObject() runtime.Object { func (in *KprobeProgramInfo) DeepCopyInto(out *KprobeProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]KprobeAttachInfo, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KprobeProgramInfo. @@ -984,17 +1218,80 @@ func (in *KprobeProgramSpec) DeepCopy() *KprobeProgramSpec { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KprobeProgramStatus) DeepCopyInto(out *KprobeProgramStatus) { +func (in *TcAttachInfo) DeepCopyInto(out *TcAttachInfo) { + *out = *in + in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) + if in.Containers != nil { + in, out := &in.Containers, &out.Containers + *out = new(ContainerSelector) + (*in).DeepCopyInto(*out) + } + if in.ProceedOn != nil { + in, out := &in.ProceedOn, &out.ProceedOn + *out = make([]TcProceedOnValue, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcAttachInfo. +func (in *TcAttachInfo) DeepCopy() *TcAttachInfo { + if in == nil { + return nil + } + out := new(TcAttachInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TcAttachInfoState) DeepCopyInto(out *TcAttachInfoState) { + *out = *in + in.AttachInfoCommon.DeepCopyInto(&out.AttachInfoCommon) + if in.AttachId != nil { + in, out := &in.AttachId, &out.AttachId + *out = new(uint32) + **out = **in + } + if in.ContainerPid != nil { + in, out := &in.ContainerPid, &out.ContainerPid + *out = new(uint32) + **out = **in + } + if in.ProceedOn != nil { + in, out := &in.ProceedOn, &out.ProceedOn + *out = make([]TcProceedOnValue, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcAttachInfoState. +func (in *TcAttachInfoState) DeepCopy() *TcAttachInfoState { + if in == nil { + return nil + } + out := new(TcAttachInfoState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TcNsAttachInfo) DeepCopyInto(out *TcNsAttachInfo) { *out = *in - in.BpfProgramStatusCommon.DeepCopyInto(&out.BpfProgramStatusCommon) + in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) + in.Containers.DeepCopyInto(&out.Containers) + if in.ProceedOn != nil { + in, out := &in.ProceedOn, &out.ProceedOn + *out = make([]TcProceedOnValue, len(*in)) + copy(*out, *in) + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KprobeProgramStatus. -func (in *KprobeProgramStatus) DeepCopy() *KprobeProgramStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcNsAttachInfo. +func (in *TcNsAttachInfo) DeepCopy() *TcNsAttachInfo { if in == nil { return nil } - out := new(KprobeProgramStatus) + out := new(TcNsAttachInfo) in.DeepCopyInto(out) return out } @@ -1030,12 +1327,12 @@ func (in *TcNsProgram) DeepCopyObject() runtime.Object { func (in *TcNsProgramInfo) DeepCopyInto(out *TcNsProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) - in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) - in.Containers.DeepCopyInto(&out.Containers) - if in.ProceedOn != nil { - in, out := &in.ProceedOn, &out.ProceedOn - *out = make([]TcProceedOnValue, len(*in)) - copy(*out, *in) + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]TcNsAttachInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } @@ -1129,16 +1426,12 @@ func (in *TcProgram) DeepCopyObject() runtime.Object { func (in *TcProgramInfo) DeepCopyInto(out *TcProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) - in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) - if in.Containers != nil { - in, out := &in.Containers, &out.Containers - *out = new(ContainerSelector) - (*in).DeepCopyInto(*out) - } - if in.ProceedOn != nil { - in, out := &in.ProceedOn, &out.ProceedOn - *out = make([]TcProceedOnValue, len(*in)) - copy(*out, *in) + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]TcAttachInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } @@ -1152,6 +1445,28 @@ func (in *TcProgramInfo) DeepCopy() *TcProgramInfo { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TcProgramInfoState) DeepCopyInto(out *TcProgramInfoState) { + *out = *in + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]TcAttachInfoState, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcProgramInfoState. +func (in *TcProgramInfoState) DeepCopy() *TcProgramInfoState { + if in == nil { + return nil + } + out := new(TcProgramInfoState) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TcProgramList) DeepCopyInto(out *TcProgramList) { *out = *in @@ -1202,17 +1517,60 @@ func (in *TcProgramSpec) DeepCopy() *TcProgramSpec { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TcProgramStatus) DeepCopyInto(out *TcProgramStatus) { +func (in *TcxAttachInfo) DeepCopyInto(out *TcxAttachInfo) { + *out = *in + in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) + if in.Containers != nil { + in, out := &in.Containers, &out.Containers + *out = new(ContainerSelector) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcxAttachInfo. +func (in *TcxAttachInfo) DeepCopy() *TcxAttachInfo { + if in == nil { + return nil + } + out := new(TcxAttachInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TcxAttachInfoState) DeepCopyInto(out *TcxAttachInfoState) { *out = *in - in.BpfProgramStatusCommon.DeepCopyInto(&out.BpfProgramStatusCommon) + in.AttachInfoCommon.DeepCopyInto(&out.AttachInfoCommon) + if in.ContainerPid != nil { + in, out := &in.ContainerPid, &out.ContainerPid + *out = new(uint32) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcProgramStatus. -func (in *TcProgramStatus) DeepCopy() *TcProgramStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcxAttachInfoState. +func (in *TcxAttachInfoState) DeepCopy() *TcxAttachInfoState { if in == nil { return nil } - out := new(TcProgramStatus) + out := new(TcxAttachInfoState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TcxNsAttachInfo) DeepCopyInto(out *TcxNsAttachInfo) { + *out = *in + in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) + in.Containers.DeepCopyInto(&out.Containers) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcxNsAttachInfo. +func (in *TcxNsAttachInfo) DeepCopy() *TcxNsAttachInfo { + if in == nil { + return nil + } + out := new(TcxNsAttachInfo) in.DeepCopyInto(out) return out } @@ -1248,8 +1606,13 @@ func (in *TcxNsProgram) DeepCopyObject() runtime.Object { func (in *TcxNsProgramInfo) DeepCopyInto(out *TcxNsProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) - in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) - in.Containers.DeepCopyInto(&out.Containers) + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]TcxNsAttachInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcxNsProgramInfo. @@ -1342,11 +1705,12 @@ func (in *TcxProgram) DeepCopyObject() runtime.Object { func (in *TcxProgramInfo) DeepCopyInto(out *TcxProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) - in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) - if in.Containers != nil { - in, out := &in.Containers, &out.Containers - *out = new(ContainerSelector) - (*in).DeepCopyInto(*out) + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]TcxAttachInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } @@ -1360,6 +1724,28 @@ func (in *TcxProgramInfo) DeepCopy() *TcxProgramInfo { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TcxProgramInfoState) DeepCopyInto(out *TcxProgramInfoState) { + *out = *in + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]TcxAttachInfoState, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcxProgramInfoState. +func (in *TcxProgramInfoState) DeepCopy() *TcxProgramInfoState { + if in == nil { + return nil + } + out := new(TcxProgramInfoState) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TcxProgramList) DeepCopyInto(out *TcxProgramList) { *out = *in @@ -1410,17 +1796,16 @@ func (in *TcxProgramSpec) DeepCopy() *TcxProgramSpec { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TcxProgramStatus) DeepCopyInto(out *TcxProgramStatus) { +func (in *TracepointAttachInfo) DeepCopyInto(out *TracepointAttachInfo) { *out = *in - in.BpfProgramStatusCommon.DeepCopyInto(&out.BpfProgramStatusCommon) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcxProgramStatus. -func (in *TcxProgramStatus) DeepCopy() *TcxProgramStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TracepointAttachInfo. +func (in *TracepointAttachInfo) DeepCopy() *TracepointAttachInfo { if in == nil { return nil } - out := new(TcxProgramStatus) + out := new(TracepointAttachInfo) in.DeepCopyInto(out) return out } @@ -1456,9 +1841,9 @@ func (in *TracepointProgram) DeepCopyObject() runtime.Object { func (in *TracepointProgramInfo) DeepCopyInto(out *TracepointProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) - if in.Names != nil { - in, out := &in.Names, &out.Names - *out = make([]string, len(*in)) + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]TracepointAttachInfo, len(*in)) copy(*out, *in) } } @@ -1523,17 +1908,37 @@ func (in *TracepointProgramSpec) DeepCopy() *TracepointProgramSpec { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TracepointProgramStatus) DeepCopyInto(out *TracepointProgramStatus) { +func (in *UprobeAttachInfo) DeepCopyInto(out *UprobeAttachInfo) { + *out = *in + if in.Containers != nil { + in, out := &in.Containers, &out.Containers + *out = new(ContainerSelector) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UprobeAttachInfo. +func (in *UprobeAttachInfo) DeepCopy() *UprobeAttachInfo { + if in == nil { + return nil + } + out := new(UprobeAttachInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UprobeNsAttachInfo) DeepCopyInto(out *UprobeNsAttachInfo) { *out = *in - in.BpfProgramStatusCommon.DeepCopyInto(&out.BpfProgramStatusCommon) + in.Containers.DeepCopyInto(&out.Containers) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TracepointProgramStatus. -func (in *TracepointProgramStatus) DeepCopy() *TracepointProgramStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UprobeNsAttachInfo. +func (in *UprobeNsAttachInfo) DeepCopy() *UprobeNsAttachInfo { if in == nil { return nil } - out := new(TracepointProgramStatus) + out := new(UprobeNsAttachInfo) in.DeepCopyInto(out) return out } @@ -1569,7 +1974,13 @@ func (in *UprobeNsProgram) DeepCopyObject() runtime.Object { func (in *UprobeNsProgramInfo) DeepCopyInto(out *UprobeNsProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) - in.Containers.DeepCopyInto(&out.Containers) + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]UprobeNsAttachInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UprobeNsProgramInfo. @@ -1662,10 +2073,12 @@ func (in *UprobeProgram) DeepCopyObject() runtime.Object { func (in *UprobeProgramInfo) DeepCopyInto(out *UprobeProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) - if in.Containers != nil { - in, out := &in.Containers, &out.Containers - *out = new(ContainerSelector) - (*in).DeepCopyInto(*out) + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]UprobeAttachInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } @@ -1729,17 +2142,75 @@ func (in *UprobeProgramSpec) DeepCopy() *UprobeProgramSpec { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UprobeProgramStatus) DeepCopyInto(out *UprobeProgramStatus) { +func (in *XdpAttachInfo) DeepCopyInto(out *XdpAttachInfo) { *out = *in - in.BpfProgramStatusCommon.DeepCopyInto(&out.BpfProgramStatusCommon) + in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) + if in.Containers != nil { + in, out := &in.Containers, &out.Containers + *out = new(ContainerSelector) + (*in).DeepCopyInto(*out) + } + if in.ProceedOn != nil { + in, out := &in.ProceedOn, &out.ProceedOn + *out = make([]XdpProceedOnValue, len(*in)) + copy(*out, *in) + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UprobeProgramStatus. -func (in *UprobeProgramStatus) DeepCopy() *UprobeProgramStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new XdpAttachInfo. +func (in *XdpAttachInfo) DeepCopy() *XdpAttachInfo { if in == nil { return nil } - out := new(UprobeProgramStatus) + out := new(XdpAttachInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *XdpAttachInfoState) DeepCopyInto(out *XdpAttachInfoState) { + *out = *in + in.AttachInfoCommon.DeepCopyInto(&out.AttachInfoCommon) + if in.ContainerPid != nil { + in, out := &in.ContainerPid, &out.ContainerPid + *out = new(uint32) + **out = **in + } + if in.ProceedOn != nil { + in, out := &in.ProceedOn, &out.ProceedOn + *out = make([]XdpProceedOnValue, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new XdpAttachInfoState. +func (in *XdpAttachInfoState) DeepCopy() *XdpAttachInfoState { + if in == nil { + return nil + } + out := new(XdpAttachInfoState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *XdpNsAttachInfo) DeepCopyInto(out *XdpNsAttachInfo) { + *out = *in + in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) + in.Containers.DeepCopyInto(&out.Containers) + if in.ProceedOn != nil { + in, out := &in.ProceedOn, &out.ProceedOn + *out = make([]XdpProceedOnValue, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new XdpNsAttachInfo. +func (in *XdpNsAttachInfo) DeepCopy() *XdpNsAttachInfo { + if in == nil { + return nil + } + out := new(XdpNsAttachInfo) in.DeepCopyInto(out) return out } @@ -1775,12 +2246,12 @@ func (in *XdpNsProgram) DeepCopyObject() runtime.Object { func (in *XdpNsProgramInfo) DeepCopyInto(out *XdpNsProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) - in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) - in.Containers.DeepCopyInto(&out.Containers) - if in.ProceedOn != nil { - in, out := &in.ProceedOn, &out.ProceedOn - *out = make([]XdpProceedOnValue, len(*in)) - copy(*out, *in) + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]XdpNsAttachInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } @@ -1874,16 +2345,12 @@ func (in *XdpProgram) DeepCopyObject() runtime.Object { func (in *XdpProgramInfo) DeepCopyInto(out *XdpProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) - in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) - if in.Containers != nil { - in, out := &in.Containers, &out.Containers - *out = new(ContainerSelector) - (*in).DeepCopyInto(*out) - } - if in.ProceedOn != nil { - in, out := &in.ProceedOn, &out.ProceedOn - *out = make([]XdpProceedOnValue, len(*in)) - copy(*out, *in) + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]XdpAttachInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } @@ -1897,6 +2364,28 @@ func (in *XdpProgramInfo) DeepCopy() *XdpProgramInfo { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *XdpProgramInfoState) DeepCopyInto(out *XdpProgramInfoState) { + *out = *in + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]XdpAttachInfoState, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new XdpProgramInfoState. +func (in *XdpProgramInfoState) DeepCopy() *XdpProgramInfoState { + if in == nil { + return nil + } + out := new(XdpProgramInfoState) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *XdpProgramList) DeepCopyInto(out *XdpProgramList) { *out = *in @@ -1949,7 +2438,7 @@ func (in *XdpProgramSpec) DeepCopy() *XdpProgramSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *XdpProgramStatus) DeepCopyInto(out *XdpProgramStatus) { *out = *in - in.BpfProgramStatusCommon.DeepCopyInto(&out.BpfProgramStatusCommon) + in.BpfAppStatus.DeepCopyInto(&out.BpfAppStatus) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new XdpProgramStatus. diff --git a/apis/v1alpha1/zz_generated.register.go b/apis/v1alpha1/zz_generated.register.go index 569ccddcd..6079cf936 100644 --- a/apis/v1alpha1/zz_generated.register.go +++ b/apis/v1alpha1/zz_generated.register.go @@ -63,6 +63,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &BpfApplication{}, &BpfApplicationList{}, + &BpfApplicationState{}, + &BpfApplicationStateList{}, &BpfNsApplication{}, &BpfNsApplicationList{}, &BpfNsProgram{}, diff --git a/bundle/manifests/bpfman-agent-role_rbac.authorization.k8s.io_v1_clusterrole.yaml b/bundle/manifests/bpfman-agent-role_rbac.authorization.k8s.io_v1_clusterrole.yaml index 40fc33a2c..3025691b6 100644 --- a/bundle/manifests/bpfman-agent-role_rbac.authorization.k8s.io_v1_clusterrole.yaml +++ b/bundle/manifests/bpfman-agent-role_rbac.authorization.k8s.io_v1_clusterrole.yaml @@ -18,6 +18,32 @@ rules: - bpfapplications/finalizers verbs: - update +- apiGroups: + - bpfman.io + resources: + - bpfapplicationstates + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - bpfman.io + resources: + - bpfapplicationstates/finalizers + verbs: + - update +- apiGroups: + - bpfman.io + resources: + - bpfapplicationstates/status + verbs: + - get + - patch + - update - apiGroups: - bpfman.io resources: diff --git a/bundle/manifests/bpfman-config_v1_configmap.yaml b/bundle/manifests/bpfman-config_v1_configmap.yaml index 545bfc394..db569c0d4 100644 --- a/bundle/manifests/bpfman-config_v1_configmap.yaml +++ b/bundle/manifests/bpfman-config_v1_configmap.yaml @@ -2,7 +2,7 @@ apiVersion: v1 data: bpfman.agent.healthprobe.addr: :8175 bpfman.agent.image: quay.io/bpfman/bpfman-agent:latest - bpfman.agent.log.level: info + bpfman.agent.log.level: debug bpfman.agent.metric.addr: 127.0.0.1:8174 bpfman.image: quay.io/bpfman/bpfman:latest bpfman.log.level: info diff --git a/bundle/manifests/bpfman-operator.clusterserviceversion.yaml b/bundle/manifests/bpfman-operator.clusterserviceversion.yaml index 82845e608..9e8ba006e 100644 --- a/bundle/manifests/bpfman-operator.clusterserviceversion.yaml +++ b/bundle/manifests/bpfman-operator.clusterserviceversion.yaml @@ -16,81 +16,65 @@ metadata: "spec": { "bytecode": { "image": { - "url": "quay.io/bpfman-bytecode/go-app-counter:latest" + "url": "quay.io/bpfman-bytecode/app-test:latest" } }, "nodeselector": {}, "programs": [ { - "kprobe": { - "bpffunctionname": "kprobe_counter", - "func_name": "try_to_wake_up", - "offset": 0, - "retprobe": false - }, - "type": "Kprobe" - }, - { - "tracepoint": { - "bpffunctionname": "tracepoint_kill_recorder", - "names": [ - "syscalls/sys_enter_kill" - ] - }, - "type": "Tracepoint" - }, - { - "tc": { - "bpffunctionname": "stats", - "direction": "ingress", - "interfaceselector": { - "primarynodeinterface": true - }, - "priority": 55 - }, - "type": "TC" - }, - { + "bpffunctionname": "tcx_next", "tcx": { - "bpffunctionname": "tcx_stats", - "direction": "ingress", - "interfaceselector": { - "primarynodeinterface": true - }, - "priority": 500 + "attach_points": [ + { + "direction": "ingress", + "interfaceselector": { + "primarynodeinterface": true + }, + "priority": 500 + } + ] }, "type": "TCX" }, { - "type": "Uprobe", - "uprobe": { - "bpffunctionname": "uprobe_counter", - "containers": { - "containernames": [ - "bpfman", - "bpfman-agent" - ], - "namespace": "bpfman", - "pods": { - "matchLabels": { - "name": "bpfman-daemon" - } + "bpffunctionname": "xdp_pass", + "type": "XDP", + "xdp": { + "attach_points": [ + { + "interfaceselector": { + "primarynodeinterface": true + }, + "priority": 55 + }, + { + "containers": { + "containernames": [ + "bpfman", + "bpfman-agent" + ], + "namespace": "bpfman", + "pods": { + "matchLabels": { + "name": "bpfman-daemon" + } + } + }, + "interfaceselector": { + "primarynodeinterface": true + }, + "priority": 100 } - }, - "func_name": "malloc", - "retprobe": false, - "target": "libc" + ] } }, { - "type": "XDP", - "xdp": { - "bpffunctionname": "xdp_stats", - "interfaceselector": { - "primarynodeinterface": true - }, - "priority": 55 - } + "bpffunctionname": "fentry_test", + "fentry": { + "attach": true, + "function_name": "do_unlinkat" + }, + "type": "Fentry" } ] } @@ -619,7 +603,7 @@ metadata: capabilities: Basic Install categories: OpenShift Optional containerImage: quay.io/bpfman/bpfman-operator:latest - createdAt: "2025-01-08T17:26:28Z" + createdAt: "2025-01-31T21:55:14Z" features.operators.openshift.io/cnf: "false" features.operators.openshift.io/cni: "false" features.operators.openshift.io/csi: "true" @@ -669,6 +653,9 @@ spec: kind: BpfApplication name: bpfapplications.bpfman.io version: v1alpha1 + - kind: BpfApplicationState + name: bpfapplicationstates.bpfman.io + version: v1alpha1 - description: BpfNsApplication is the Schema for the BpfNsApplications API displayName: Bpf Namespaced Application kind: BpfNsApplication @@ -1105,6 +1092,14 @@ spec: - get - patch - update + - apiGroups: + - bpfman.io + resources: + - bpfapplicationstates + verbs: + - get + - list + - watch - apiGroups: - bpfman.io resources: diff --git a/bundle/manifests/bpfman.io_bpfapplications.yaml b/bundle/manifests/bpfman.io_bpfapplications.yaml index fde48711d..1507d5f66 100644 --- a/bundle/manifests/bpfman.io_bpfapplications.yaml +++ b/bundle/manifests/bpfman.io_bpfapplications.yaml @@ -104,6 +104,56 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object + mapownerselector: + description: |- + MapOwnerSelector is used to select the loaded eBPF program this eBPF program + will share a map with. The value is a label applied to the BpfProgram to select. + The selector must resolve to exactly one instance of a BpfProgram on a given node + or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic nodeselector: description: |- NodeSelector allows the user to specify which nodes to deploy the @@ -155,31 +205,45 @@ spec: x-kubernetes-map-type: atomic programs: description: |- - Programs is a list of bpf programs supported for a specific application. - It's possible that the application can selectively choose which program(s) - to run from this list. + Programs is the list of bpf programs in the BpfApplication that should be + loaded. The application can selectively choose which program(s) to run + from this list based on the optional attach points provided. items: description: BpfApplicationProgram defines the desired state of BpfApplication properties: + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string fentry: description: fentry defines the desired state of the application's FentryPrograms. properties: + attach: + description: Whether the bpf program should be attached + to the function. + type: boolean bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF program type: string - func_name: - description: Function to attach the fentry to. + function_name: + description: FunctionName is the name of the function to + attach the Fentry program to. type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -225,27 +289,35 @@ spec: type: object x-kubernetes-map-type: atomic required: + - attach - bpffunctionname - - func_name + - function_name type: object fexit: description: fexit defines the desired state of the application's FexitPrograms. properties: + attach: + type: boolean bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF program type: string - func_name: - description: Function to attach the fexit to. + function_name: + description: FunctionName is the name of the function to + attach the Fexit program to. type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -291,27 +363,57 @@ spec: type: object x-kubernetes-map-type: atomic required: + - attach - bpffunctionname - - func_name + - function_name type: object kprobe: description: kprobe defines the desired state of the application's KprobePrograms. properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + func_name: + description: Functions to attach the kprobe to. + type: string + offset: + default: 0 + description: |- + Offset added to the address of the function for kprobe. + Not allowed for kretprobes. + format: int64 + type: integer + retprobe: + default: false + description: Whether the program is a kretprobe. Default + is false + type: boolean + required: + - func_name + type: object + x-kubernetes-validations: + - message: offset cannot be set for kretprobes + rule: self.retprobe == false || self.offset == 0 + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF program type: string - func_name: - description: Functions to attach the kprobe to. - type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -356,40 +458,56 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: |- - Offset added to the address of the function for kprobe. - Not allowed for kretprobes. - format: int64 - type: integer - retprobe: - default: false - description: Whether the program is a kretprobe. Default - is false - type: boolean required: - bpffunctionname - - func_name type: object kretprobe: description: kretprobe defines the desired state of the application's KretprobePrograms. properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + func_name: + description: Functions to attach the kprobe to. + type: string + offset: + default: 0 + description: |- + Offset added to the address of the function for kprobe. + Not allowed for kretprobes. + format: int64 + type: integer + retprobe: + default: false + description: Whether the program is a kretprobe. Default + is false + type: boolean + required: + - func_name + type: object + x-kubernetes-validations: + - message: offset cannot be set for kretprobes + rule: self.retprobe == false || self.offset == 0 + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF program type: string - func_name: - description: Functions to attach the kprobe to. - type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -434,131 +552,221 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: |- - Offset added to the address of the function for kprobe. - Not allowed for kretprobes. - format: int64 - type: integer - retprobe: - default: false - description: Whether the program is a kretprobe. Default - is false - type: boolean required: - bpffunctionname - - func_name type: object + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic tc: description: tc defines the desired state of the application's TcPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tc program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pipe + - dispatcher_return + description: |- + ProceedOn allows the user to call other tc programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - unspec + - ok + - reclassify + - shot + - pipe + - stolen + - queued + - repeat + - redirect + - trap + - dispatcher_return + type: string + maxItems: 11 + type: array + required: + - direction + - interfaceselector + - priority + type: object + type: array + bpffunctionname: description: |- - Direction specifies the direction of traffic the tc program should - attach to for a given network device. - enum: - - ingress - - egress + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - interfaceselector: - description: Selector to determine the network interface - (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface - on the node. Only 'true' accepted. - type: boolean - type: object - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -603,153 +811,144 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pipe - - dispatcher_return - description: |- - ProceedOn allows the user to call other tc programs in chain on this exit code. - Multiple values are supported by repeating the parameter. - items: - enum: - - unspec - - ok - - reclassify - - shot - - pipe - - stolen - - queued - - repeat - - redirect - - trap - - dispatcher_return - type: string - maxItems: 11 - type: array required: - bpffunctionname - - direction - - interfaceselector - - priority type: object tcx: description: tcx defines the desired state of the application's TcxPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tcx program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tcx program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + required: + - direction + - interfaceselector + - priority + type: object + type: array + bpffunctionname: description: |- - Direction specifies the direction of traffic the tcx program should - attach to for a given network device. - enum: - - ingress - - egress + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - interfaceselector: - description: Selector to determine the network interface - (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface - on the node. Only 'true' accepted. - type: boolean - type: object - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -794,36 +993,43 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer required: - bpffunctionname - - direction - - interfaceselector - - priority type: object tracepoint: description: tracepoint defines the desired state of the application's TracepointPrograms. properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + name: + description: |- + Name refers to the name of a kernel tracepoint to attach the + bpf program to. + type: string + required: + - name + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF program type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -868,16 +1074,8 @@ spec: type: object type: object x-kubernetes-map-type: atomic - names: - description: |- - Names refers to the names of kernel tracepoints to attach the - bpf program to. - items: - type: string - type: array required: - bpffunctionname - - names type: object type: description: Type specifies the bpf program type @@ -897,91 +1095,127 @@ spec: description: uprobe defines the desired state of the application's UprobePrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the uprobe. - If Containers is not specified, the uprobe will be attached in the - bpfman-agent container. The ContainerSelector is very flexible and even - allows the selection of all containers in a cluster. If an attempt is - made to attach uprobes to too many containers, it can have a negative - impact on on the cluster. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the uprobe. + If Containers is not specified, the uprobe will be attached in the + bpfman-agent container. The ContainerSelector is very flexible and even + allows the selection of all containers in a cluster. If an attempt is + made to attach uprobes to too many containers, it can have a negative + impact on on the cluster. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - func_name: - description: Function to attach the uprobe to. + x-kubernetes-map-type: atomic + required: + - pods + type: object + func_name: + description: Function to attach the uprobe to. + type: string + offset: + default: 0 + description: Offset added to the address of the function + for uprobe. + format: int64 + type: integer + pid: + description: |- + Only execute uprobe for given process identification number (PID). If PID + is not provided, uprobe executes for all PIDs. + format: int32 + type: integer + retprobe: + default: false + description: Whether the program is a uretprobe. Default + is false + type: boolean + target: + description: Library name or the absolute path to + a binary or library. + type: string + required: + - target + type: object + type: array + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -1026,120 +1260,134 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: Offset added to the address of the function - for uprobe. - format: int64 - type: integer - pid: - description: |- - Only execute uprobe for given process identification number (PID). If PID - is not provided, uprobe executes for all PIDs. - format: int32 - type: integer - retprobe: - default: false - description: Whether the program is a uretprobe. Default - is false - type: boolean - target: - description: Library name or the absolute path to a binary - or library. - type: string required: - bpffunctionname - - target type: object uretprobe: description: uretprobe defines the desired state of the application's UretprobePrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the uprobe. - If Containers is not specified, the uprobe will be attached in the - bpfman-agent container. The ContainerSelector is very flexible and even - allows the selection of all containers in a cluster. If an attempt is - made to attach uprobes to too many containers, it can have a negative - impact on on the cluster. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the uprobe. + If Containers is not specified, the uprobe will be attached in the + bpfman-agent container. The ContainerSelector is very flexible and even + allows the selection of all containers in a cluster. If an attempt is + made to attach uprobes to too many containers, it can have a negative + impact on on the cluster. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - func_name: - description: Function to attach the uprobe to. + x-kubernetes-map-type: atomic + required: + - pods + type: object + func_name: + description: Function to attach the uprobe to. + type: string + offset: + default: 0 + description: Offset added to the address of the function + for uprobe. + format: int64 + type: integer + pid: + description: |- + Only execute uprobe for given process identification number (PID). If PID + is not provided, uprobe executes for all PIDs. + format: int32 + type: integer + retprobe: + default: false + description: Whether the program is a uretprobe. Default + is false + type: boolean + target: + description: Library name or the absolute path to + a binary or library. + type: string + required: + - target + type: object + type: array + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -1184,132 +1432,153 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: Offset added to the address of the function - for uprobe. - format: int64 - type: integer - pid: - description: |- - Only execute uprobe for given process identification number (PID). If PID - is not provided, uprobe executes for all PIDs. - format: int32 - type: integer - retprobe: - default: false - description: Whether the program is a uretprobe. Default - is false - type: boolean - target: - description: Library name or the absolute path to a binary - or library. - type: string required: - bpffunctionname - - target type: object xdp: description: xdp defines the desired state of the application's XdpPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - interfaceselector: - description: Selector to determine the network interface - (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface - on the node. Only 'true' accepted. - type: boolean - type: object - mapownerselector: + x-kubernetes-map-type: atomic + required: + - pods + type: object + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the bpf program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pass + - dispatcher_return + description: |- + ProceedOn allows the user to call other xdp programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + required: + - interfaceselector + - priority + type: object + type: array + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -1354,35 +1623,11 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the bpf program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pass - - dispatcher_return - items: - enum: - - aborted - - drop - - pass - - tx - - redirect - - dispatcher_return - type: string - maxItems: 6 - type: array required: - bpffunctionname - - interfaceselector - - priority type: object + required: + - bpffunctionname type: object x-kubernetes-validations: - message: xdp configuration is required when type is XDP, and forbidden @@ -1425,19 +1670,20 @@ spec: and forbidden otherwise rule: 'has(self.type) && self.type == ''Tracepoint'' ? has(self.tracepoint) : !has(self.tracepoint)' - minItems: 1 type: array required: - bytecode - nodeselector type: object status: - description: BpfApplicationStatus defines the observed state of BpfApplication + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_bpfapplicationstates.yaml b/bundle/manifests/bpfman.io_bpfapplicationstates.yaml new file mode 100644 index 000000000..fa34e7a01 --- /dev/null +++ b/bundle/manifests/bpfman.io_bpfapplicationstates.yaml @@ -0,0 +1,638 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + creationTimestamp: null + name: bpfapplicationstates.bpfman.io +spec: + group: bpfman.io + names: + kind: BpfApplicationState + listKind: BpfApplicationStateList + plural: bpfapplicationstates + singular: bpfapplicationstate + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[0].reason + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + BpfApplicationState contains the per-node state of a BpfApplication. + ANF-TODO: I can't get the Node to display in the kubectl output. + // +kubebuilder:printcolumn:name="Node",type=string,JSONPath=".metadata.labels['kubernetes.io/hostname']" + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: BpfApplicationSpec defines the desired state of BpfApplication + properties: + apploadstatus: + description: |- + AppLoadStatus reflects the status of loading the bpf application on the + given node. + type: string + node: + description: Node is the name of the node for this BpfApplicationStateSpec. + type: string + programs: + description: |- + Programs is a list of bpf programs contained in the parent application. + It is a map from the bpf program name to BpfApplicationProgramState + elements. + items: + description: |- + BpfApplicationProgramState defines the desired state of BpfApplication + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'TC' ? has(self.tc) : !has(self.tc)",message="tc configuration is required when type is TC, and forbidden otherwise" + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Fexit' ? has(self.fexit) : !has(self.fexit)",message="fexit configuration is required when type is Fexit, and forbidden otherwise" + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Kprobe' ? has(self.kprobe) : !has(self.kprobe)",message="kprobe configuration is required when type is Kprobe, and forbidden otherwise" + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Kretprobe' ? has(self.kretprobe) : !has(self.kretprobe)",message="kretprobe configuration is required when type is Kretprobe, and forbidden otherwise" + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Uprobe' ? has(self.uprobe) : !has(self.uprobe)",message="uprobe configuration is required when type is Uprobe, and forbidden otherwise" + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Uretprobe' ? has(self.uretprobe) : !has(self.uretprobe)",message="uretprobe configuration is required when type is Uretprobe, and forbidden otherwise" + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Tracepoint' ? has(self.tracepoint) : !has(self.tracepoint)",message="tracepoint configuration is required when type is Tracepoint, and forbidden otherwise" + properties: + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + fentry: + description: fentry defines the desired state of the application's + FentryPrograms. + properties: + attach: + type: boolean + attachid: + description: |- + An identifier for the attach point assigned by bpfman. This field is + empty until the program is successfully attached and bpfman returns the + id. + ANF-TODO: For the POC, this will be the program ID. + format: int32 + type: integer + attachstatus: + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. + type: string + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + function_name: + description: FunctionName is the name of the function to + attach the Fentry program to. + type: string + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + program_id: + description: |- + ProgramId is the id of the program in the kernel. Not set until the + program is loaded. + format: int32 + type: integer + programattachstatus: + description: |- + ProgramAttachStatus records whether the program should be loaded and whether + the program is loaded. + type: string + should_attach: + description: ShouldAttach reflects whether the attachment + should exist. + type: boolean + uuid: + description: |- + ANF-TODO: Putting a uuid here for now to maintain compatibility with the + existing BpfProgram. + type: string + required: + - attach + - attachid + - attachstatus + - bpffunctionname + - function_name + - programattachstatus + - should_attach + - uuid + type: object + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + program_id: + description: |- + ProgramId is the id of the program in the kernel. Not set until the + program is loaded. + format: int32 + type: integer + programattachstatus: + description: |- + ProgramAttachStatus records whether the program should be loaded and whether + the program is loaded. + type: string + tc: + description: tc defines the desired state of the application's + TcPrograms. + properties: + attach_points: + description: |- + The list of points to which the program should be attached. + TcAttachInfoState is similar to TcAttachInfo, but the interface and + container selectors are expanded, and we have one instance of + TcAttachInfoState for each unique attach point. The list is optional and + may be udated after the bpf program has been loaded. + items: + properties: + attachid: + description: |- + An identifier for the attach point assigned by bpfman. This field is + empty until the program is successfully attached and bpfman returns the + id. + ANF-TODO: For the POC, this will be the program ID. + format: int32 + type: integer + attachstatus: + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. + type: string + containerpid: + description: Optional container pid to attach the + tc program in. + format: int32 + type: integer + direction: + description: |- + Direction specifies the direction of traffic the tc program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + ifname: + description: Interface name to attach the tc program + to. + type: string + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + description: |- + ProceedOn allows the user to call other tc programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - unspec + - ok + - reclassify + - shot + - pipe + - stolen + - queued + - repeat + - redirect + - trap + - dispatcher_return + type: string + maxItems: 11 + type: array + should_attach: + description: ShouldAttach reflects whether the attachment + should exist. + type: boolean + uuid: + description: |- + ANF-TODO: Putting a uuid here for now to maintain compatibility with the + existing BpfProgram. + type: string + required: + - attachid + - attachstatus + - direction + - ifname + - priority + - proceedon + - should_attach + - uuid + type: object + type: array + type: object + tcx: + description: tcx defines the desired state of the application's + TcxPrograms. + properties: + attach_points: + description: |- + The list of points to which the program should be attached. + TcxAttachInfoState is similar to TcxAttachInfo, but the interface and + container selectors are expanded, and we have one instance of + TcxAttachInfoState for each unique attach point. The list is optional and + may be udated after the bpf program has been loaded. + items: + properties: + attachid: + description: |- + An identifier for the attach point assigned by bpfman. This field is + empty until the program is successfully attached and bpfman returns the + id. + ANF-TODO: For the POC, this will be the program ID. + format: int32 + type: integer + attachstatus: + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. + type: string + containerpid: + description: Optional container pid to attach the + tcx program in. + format: int32 + type: integer + direction: + description: |- + Direction specifies the direction of traffic the tcx program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + ifname: + description: Interface name to attach the tcx program + to. + type: string + priority: + description: |- + Priority specifies the priority of the tcx program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + should_attach: + description: ShouldAttach reflects whether the attachment + should exist. + type: boolean + uuid: + description: |- + ANF-TODO: Putting a uuid here for now to maintain compatibility with the + existing BpfProgram. + type: string + required: + - attachid + - attachstatus + - direction + - ifname + - priority + - should_attach + - uuid + type: object + type: array + type: object + type: + description: Type specifies the bpf program type + enum: + - XDP + - TC + - TCX + - Fentry + - Fexit + - Kprobe + - Kretprobe + - Uprobe + - Uretprobe + - Tracepoint + type: string + xdp: + description: xdp defines the desired state of the application's + XdpPrograms. + properties: + attach_points: + description: |- + The list of points to which the program should be attached. + XdpAttachInfoState is similar to XdpAttachInfo, but the interface and + container selectors are expanded, and we have one instance of + XdpAttachInfoState for each unique attach point. The list is optional and + may be udated after the bpf program has been loaded. + items: + properties: + attachid: + description: |- + An identifier for the attach point assigned by bpfman. This field is + empty until the program is successfully attached and bpfman returns the + id. + ANF-TODO: For the POC, this will be the program ID. + format: int32 + type: integer + attachstatus: + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. + type: string + containerpid: + description: Optional container pid to attach the + xdp program in. + format: int32 + type: integer + ifname: + description: Interface name to attach the xdp program + to. + type: string + priority: + description: |- + Priority specifies the priority of the xdp program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + description: |- + ProceedOn allows the user to call other xdp programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + should_attach: + description: ShouldAttach reflects whether the attachment + should exist. + type: boolean + uuid: + description: |- + ANF-TODO: Putting a uuid here for now to maintain compatibility with the + existing BpfProgram. + type: string + required: + - attachid + - attachstatus + - ifname + - priority + - proceedon + - should_attach + - uuid + type: object + type: array + type: object + required: + - bpffunctionname + - programattachstatus + type: object + x-kubernetes-validations: + - message: xdp configuration is required when type is XDP, and forbidden + otherwise + rule: 'has(self.type) && self.type == ''XDP'' ? has(self.xdp) + : !has(self.xdp)' + - message: tcx configuration is required when type is TCX, and forbidden + otherwise + rule: 'has(self.type) && self.type == ''TCX'' ? has(self.tcx) + : !has(self.tcx)' + - message: fentry configuration is required when type is Fentry, + and forbidden otherwise + rule: 'has(self.type) && self.type == ''Fentry'' ? has(self.fentry) + : !has(self.fentry)' + type: array + updatecount: + description: |- + The number of times the BpfApplicationState has been updated. Set to 1 + when the object is created, then it is incremented prior to each update. + This allows us to verify that the API server has the updated object prior + to starting a new Reconcile operation. + format: int64 + type: integer + required: + - apploadstatus + - node + - updatecount + type: object + status: + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object + properties: + conditions: + description: |- + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/bundle/manifests/bpfman.io_bpfnsapplications.yaml b/bundle/manifests/bpfman.io_bpfnsapplications.yaml index 9a355155b..3a7132595 100644 --- a/bundle/manifests/bpfman.io_bpfnsapplications.yaml +++ b/bundle/manifests/bpfman.io_bpfnsapplications.yaml @@ -104,6 +104,56 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object + mapownerselector: + description: |- + MapOwnerSelector is used to select the loaded eBPF program this eBPF program + will share a map with. The value is a label applied to the BpfProgram to select. + The selector must resolve to exactly one instance of a BpfProgram on a given node + or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic nodeselector: description: |- NodeSelector allows the user to specify which nodes to deploy the @@ -166,106 +216,156 @@ spec: description: tc defines the desired state of the application's TcNsPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. + properties: + containernames: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tc program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pipe + - dispatcher_return + description: |- + ProceedOn allows the user to call other tc programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - unspec + - ok + - reclassify + - shot + - pipe + - stolen + - queued + - repeat + - redirect + - trap + - dispatcher_return + type: string + maxItems: 11 + type: array + required: + - containers + - direction + - interfaceselector + - priority + type: object + type: array + bpffunctionname: description: |- - Direction specifies the direction of traffic the tc program should - attach to for a given network device. - enum: - - ingress - - egress + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - interfaceselector: - description: Selector to determine the network interface - (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface - on the node. Only 'true' accepted. - type: boolean - type: object - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -310,149 +410,141 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pipe - - dispatcher_return - description: |- - ProceedOn allows the user to call other tc programs in chain on this exit code. - Multiple values are supported by repeating the parameter. - items: - enum: - - unspec - - ok - - reclassify - - shot - - pipe - - stolen - - queued - - repeat - - redirect - - trap - - dispatcher_return - type: string - maxItems: 11 - type: array required: - bpffunctionname - - containers - - direction - - interfaceselector - - priority type: object tcx: description: tcx defines the desired state of the application's TcxNsPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tcx program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + required: + - containers + - direction + - interfaceselector + - priority + type: object + type: array + bpffunctionname: description: |- - Direction specifies the direction of traffic the tcx program should - attach to for a given network device. - enum: - - ingress - - egress + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - interfaceselector: - description: Selector to determine the network interface - (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface - on the node. Only 'true' accepted. - type: boolean - type: object - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -497,21 +589,8 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer required: - bpffunctionname - - containers - - direction - - interfaceselector - - priority type: object type: description: Type specifies the bpf program type @@ -526,87 +605,124 @@ spec: description: uprobe defines the desired state of the application's UprobeNsPrograms. properties: - bpffunctionname: + attach_points: description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: - description: |- - Containers identifies the set of containers in which to attach the uprobe. - If Containers is not specified, the uprobe will be attached in the - bpfman-agent container. The ContainerNsSelector is very flexible and even - allows the selection of all containers in a cluster. If an attempt is - made to attach uprobes to too many containers, it can have a negative - impact on on the cluster. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the uprobe. + If Containers is not specified, the uprobe will be attached in the + bpfman-agent container. The ContainerNsSelector is very flexible and even + allows the selection of all containers in a cluster. If an attempt is + made to attach uprobes to too many containers, it can have a negative + impact on on the cluster. + properties: + containernames: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - func_name: - description: Function to attach the uprobe to. + x-kubernetes-map-type: atomic + required: + - pods + type: object + func_name: + description: Function to attach the uprobe to. + type: string + offset: + default: 0 + description: Offset added to the address of the function + for uprobe. + format: int64 + type: integer + pid: + description: |- + Only execute uprobe for given process identification number (PID). If PID + is not provided, uprobe executes for all PIDs. + format: int32 + type: integer + retprobe: + default: false + description: Whether the program is a uretprobe. Default + is false + type: boolean + target: + description: Library name or the absolute path to + a binary or library. + type: string + required: + - containers + - target + type: object + type: array + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -651,117 +767,131 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: Offset added to the address of the function - for uprobe. - format: int64 - type: integer - pid: - description: |- - Only execute uprobe for given process identification number (PID). If PID - is not provided, uprobe executes for all PIDs. - format: int32 - type: integer - retprobe: - default: false - description: Whether the program is a uretprobe. Default - is false - type: boolean - target: - description: Library name or the absolute path to a binary - or library. - type: string required: - bpffunctionname - - containers - - target type: object uretprobe: description: uretprobe defines the desired state of the application's UretprobeNsPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the uprobe. - If Containers is not specified, the uprobe will be attached in the - bpfman-agent container. The ContainerNsSelector is very flexible and even - allows the selection of all containers in a cluster. If an attempt is - made to attach uprobes to too many containers, it can have a negative - impact on on the cluster. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the uprobe. + If Containers is not specified, the uprobe will be attached in the + bpfman-agent container. The ContainerNsSelector is very flexible and even + allows the selection of all containers in a cluster. If an attempt is + made to attach uprobes to too many containers, it can have a negative + impact on on the cluster. + properties: + containernames: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - func_name: - description: Function to attach the uprobe to. + x-kubernetes-map-type: atomic + required: + - pods + type: object + func_name: + description: Function to attach the uprobe to. + type: string + offset: + default: 0 + description: Offset added to the address of the function + for uprobe. + format: int64 + type: integer + pid: + description: |- + Only execute uprobe for given process identification number (PID). If PID + is not provided, uprobe executes for all PIDs. + format: int32 + type: integer + retprobe: + default: false + description: Whether the program is a uretprobe. Default + is false + type: boolean + target: + description: Library name or the absolute path to + a binary or library. + type: string + required: + - containers + - target + type: object + type: array + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -806,128 +936,149 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: Offset added to the address of the function - for uprobe. - format: int64 - type: integer - pid: - description: |- - Only execute uprobe for given process identification number (PID). If PID - is not provided, uprobe executes for all PIDs. - format: int32 - type: integer - retprobe: - default: false - description: Whether the program is a uretprobe. Default - is false - type: boolean - target: - description: Library name or the absolute path to a binary - or library. - type: string required: - bpffunctionname - - containers - - target type: object xdp: description: xdp defines the desired state of the application's XdpNsPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - interfaceselector: - description: Selector to determine the network interface - (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface - on the node. Only 'true' accepted. - type: boolean - type: object - mapownerselector: + x-kubernetes-map-type: atomic + required: + - pods + type: object + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the bpf program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pass + - dispatcher_return + description: |- + ProceedOn allows the user to call other xdp programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + required: + - containers + - interfaceselector + - priority + type: object + type: array + bpffunctionname: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -972,38 +1123,8 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the bpf program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pass - - dispatcher_return - description: |- - ProceedOn allows the user to call other xdp programs in chain on this exit code. - Multiple values are supported by repeating the parameter. - items: - enum: - - aborted - - drop - - pass - - tx - - redirect - - dispatcher_return - type: string - maxItems: 6 - type: array required: - bpffunctionname - - containers - - interfaceselector - - priority type: object type: object x-kubernetes-validations: @@ -1034,12 +1155,14 @@ spec: - nodeselector type: object status: - description: BpfApplicationStatus defines the observed state of BpfApplication + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_fentryprograms.yaml b/bundle/manifests/bpfman.io_fentryprograms.yaml index 76cefd41c..7a39546de 100644 --- a/bundle/manifests/bpfman.io_fentryprograms.yaml +++ b/bundle/manifests/bpfman.io_fentryprograms.yaml @@ -53,6 +53,9 @@ spec: spec: description: FentryProgramSpec defines the desired state of FentryProgram properties: + attach: + description: Whether the bpf program should be attached to the function. + type: boolean bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -103,8 +106,9 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - func_name: - description: Function to attach the fentry to. + function_name: + description: FunctionName is the name of the function to attach the + Fentry program to. type: string globaldata: additionalProperties: @@ -215,19 +219,76 @@ spec: type: object type: object x-kubernetes-map-type: atomic + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: + - attach - bpffunctionname - bytecode - - func_name + - function_name - nodeselector type: object status: - description: FentryProgramStatus defines the observed state of FentryProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_fexitprograms.yaml b/bundle/manifests/bpfman.io_fexitprograms.yaml index 78225dcfb..306d5baab 100644 --- a/bundle/manifests/bpfman.io_fexitprograms.yaml +++ b/bundle/manifests/bpfman.io_fexitprograms.yaml @@ -53,6 +53,8 @@ spec: spec: description: FexitProgramSpec defines the desired state of FexitProgram properties: + attach: + type: boolean bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -103,8 +105,9 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - func_name: - description: Function to attach the fexit to. + function_name: + description: FunctionName is the name of the function to attach the + Fexit program to. type: string globaldata: additionalProperties: @@ -215,19 +218,76 @@ spec: type: object type: object x-kubernetes-map-type: atomic + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: + - attach - bpffunctionname - bytecode - - func_name + - function_name - nodeselector type: object status: - description: FexitProgramStatus defines the observed state of FexitProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_kprobeprograms.yaml b/bundle/manifests/bpfman.io_kprobeprograms.yaml index e40bed810..d8cbe3a32 100644 --- a/bundle/manifests/bpfman.io_kprobeprograms.yaml +++ b/bundle/manifests/bpfman.io_kprobeprograms.yaml @@ -61,6 +61,34 @@ spec: spec: description: KprobeProgramSpec defines the desired state of KprobeProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + func_name: + description: Functions to attach the kprobe to. + type: string + offset: + default: 0 + description: |- + Offset added to the address of the function for kprobe. + Not allowed for kretprobes. + format: int64 + type: integer + retprobe: + default: false + description: Whether the program is a kretprobe. Default is + false + type: boolean + required: + - func_name + type: object + x-kubernetes-validations: + - message: offset cannot be set for kretprobes + rule: self.retprobe == false || self.offset == 0 + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -111,9 +139,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - func_name: - description: Functions to attach the kprobe to. - type: string globaldata: additionalProperties: format: byte @@ -223,33 +248,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 + oldmapownerselector: description: |- - Offset added to the address of the function for kprobe. - Not allowed for kretprobes. - format: int64 - type: integer - retprobe: - default: false - description: Whether the program is a kretprobe. Default is false - type: boolean + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - func_name - nodeselector type: object - x-kubernetes-validations: - - message: offset cannot be set for kretprobes - rule: self.retprobe == false || self.offset == 0 status: - description: KprobeProgramStatus defines the observed state of KprobeProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_tcnsprograms.yaml b/bundle/manifests/bpfman.io_tcnsprograms.yaml index f2602002c..5ba649316 100644 --- a/bundle/manifests/bpfman.io_tcnsprograms.yaml +++ b/bundle/manifests/bpfman.io_tcnsprograms.yaml @@ -65,6 +65,140 @@ spec: spec: description: TcNsProgramSpec defines the desired state of TcNsProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tc program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface (or + interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary interface + on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pipe + - dispatcher_return + description: |- + ProceedOn allows the user to call other tc programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - unspec + - ok + - reclassify + - shot + - pipe + - stolen + - queued + - repeat + - redirect + - trap + - dispatcher_return + type: string + maxItems: 11 + type: array + required: + - containers + - direction + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -115,77 +249,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the eBPF - program. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: - description: |- - Direction specifies the direction of traffic the tc program should - attach to for a given network device. - enum: - - ingress - - egress - type: string globaldata: additionalProperties: format: byte @@ -196,23 +259,6 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object - interfaceselector: - description: Selector to determine the network interface (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface on the - node. Only 'true' accepted. - type: boolean - type: object mapownerselector: description: |- MapOwnerSelector is used to select the loaded eBPF program this eBPF program @@ -312,54 +358,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pipe - - dispatcher_return + oldmapownerselector: description: |- - ProceedOn allows the user to call other tc programs in chain on this exit code. - Multiple values are supported by repeating the parameter. - items: - enum: - - unspec - - ok - - reclassify - - shot - - pipe - - stolen - - queued - - repeat - - redirect - - trap - - dispatcher_return - type: string - maxItems: 11 - type: array + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - containers - - direction - - interfaceselector - nodeselector - - priority type: object status: - description: TcProgramStatus defines the observed state of TcProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_tcprograms.yaml b/bundle/manifests/bpfman.io_tcprograms.yaml index 6bd329110..c30b8719d 100644 --- a/bundle/manifests/bpfman.io_tcprograms.yaml +++ b/bundle/manifests/bpfman.io_tcprograms.yaml @@ -65,6 +65,144 @@ spec: spec: description: TcProgramSpec defines the desired state of TcProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tc program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface (or + interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary interface + on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pipe + - dispatcher_return + description: |- + ProceedOn allows the user to call other tc programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - unspec + - ok + - reclassify + - shot + - pipe + - stolen + - queued + - repeat + - redirect + - trap + - dispatcher_return + type: string + maxItems: 11 + type: array + required: + - direction + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -115,82 +253,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: - description: |- - Direction specifies the direction of traffic the tc program should - attach to for a given network device. - enum: - - ingress - - egress - type: string globaldata: additionalProperties: format: byte @@ -201,23 +263,6 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object - interfaceselector: - description: Selector to determine the network interface (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface on the - node. Only 'true' accepted. - type: boolean - type: object mapownerselector: description: |- MapOwnerSelector is used to select the loaded eBPF program this eBPF program @@ -317,53 +362,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: + oldmapownerselector: description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pipe - - dispatcher_return - description: |- - ProceedOn allows the user to call other tc programs in chain on this exit code. - Multiple values are supported by repeating the parameter. - items: - enum: - - unspec - - ok - - reclassify - - shot - - pipe - - stolen - - queued - - repeat - - redirect - - trap - - dispatcher_return - type: string - maxItems: 11 - type: array + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - direction - - interfaceselector - nodeselector - - priority type: object status: - description: TcProgramStatus defines the observed state of TcProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_tcxnsprograms.yaml b/bundle/manifests/bpfman.io_tcxnsprograms.yaml index 947e5c32d..1fffe83ed 100644 --- a/bundle/manifests/bpfman.io_tcxnsprograms.yaml +++ b/bundle/manifests/bpfman.io_tcxnsprograms.yaml @@ -65,6 +65,118 @@ spec: spec: description: TcxNsProgramSpec defines the desired state of TcxNsProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tcx program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface (or + interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary interface + on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + required: + - containers + - direction + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -115,77 +227,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the eBPF - program. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: - description: |- - Direction specifies the direction of traffic the tcx program should - attach to for a given network device. - enum: - - ingress - - egress - type: string globaldata: additionalProperties: format: byte @@ -196,23 +237,6 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object - interfaceselector: - description: Selector to determine the network interface (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface on the - node. Only 'true' accepted. - type: boolean - type: object mapownerselector: description: |- MapOwnerSelector is used to select the loaded eBPF program this eBPF program @@ -312,31 +336,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: + oldmapownerselector: description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - containers - - direction - - interfaceselector - nodeselector - - priority type: object status: - description: TcxProgramStatus defines the observed state of TcxProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_tcxprograms.yaml b/bundle/manifests/bpfman.io_tcxprograms.yaml index 00ee3d933..f0b1acf7a 100644 --- a/bundle/manifests/bpfman.io_tcxprograms.yaml +++ b/bundle/manifests/bpfman.io_tcxprograms.yaml @@ -24,6 +24,10 @@ spec: - jsonPath: .status.conditions[0].reason name: Status type: string + - jsonPath: .spec.priority + name: Priority + priority: 1 + type: string - jsonPath: .spec.direction name: Direction priority: 1 @@ -36,10 +40,6 @@ spec: name: Position priority: 1 type: string - - jsonPath: .spec.priority - name: Priority - priority: 1 - type: string name: v1alpha1 schema: openAPIV3Schema: @@ -65,6 +65,121 @@ spec: spec: description: TcxProgramSpec defines the desired state of TcxProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tcx program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface (or + interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary interface + on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tcx program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + required: + - direction + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -115,82 +230,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: - description: |- - Direction specifies the direction of traffic the tcx program should - attach to for a given network device. - enum: - - ingress - - egress - type: string globaldata: additionalProperties: format: byte @@ -201,23 +240,6 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object - interfaceselector: - description: Selector to determine the network interface (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface on the - node. Only 'true' accepted. - type: boolean - type: object mapownerselector: description: |- MapOwnerSelector is used to select the loaded eBPF program this eBPF program @@ -317,30 +339,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: + oldmapownerselector: description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - direction - - interfaceselector - nodeselector - - priority type: object status: - description: TcxProgramStatus defines the observed state of TcxProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_tracepointprograms.yaml b/bundle/manifests/bpfman.io_tracepointprograms.yaml index add6d12b6..32348db78 100644 --- a/bundle/manifests/bpfman.io_tracepointprograms.yaml +++ b/bundle/manifests/bpfman.io_tracepointprograms.yaml @@ -53,6 +53,21 @@ spec: spec: description: TracepointProgramSpec defines the desired state of TracepointProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + name: + description: |- + Name refers to the name of a kernel tracepoint to attach the + bpf program to. + type: string + required: + - name + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -163,13 +178,6 @@ spec: type: object type: object x-kubernetes-map-type: atomic - names: - description: |- - Names refers to the names of kernel tracepoints to attach the - bpf program to. - items: - type: string - type: array nodeselector: description: |- NodeSelector allows the user to specify which nodes to deploy the @@ -219,19 +227,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - names - nodeselector type: object status: - description: TracepointProgramStatus defines the observed state of TracepointProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_uprobensprograms.yaml b/bundle/manifests/bpfman.io_uprobensprograms.yaml index f16f7f81c..43bad0bcf 100644 --- a/bundle/manifests/bpfman.io_uprobensprograms.yaml +++ b/bundle/manifests/bpfman.io_uprobensprograms.yaml @@ -69,6 +69,108 @@ spec: spec: description: UprobeNsProgramSpec defines the desired state of UprobeProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the uprobe. + If Containers is not specified, the uprobe will be attached in the + bpfman-agent container. The ContainerNsSelector is very flexible and even + allows the selection of all containers in a cluster. If an attempt is + made to attach uprobes to too many containers, it can have a negative + impact on on the cluster. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + func_name: + description: Function to attach the uprobe to. + type: string + offset: + default: 0 + description: Offset added to the address of the function for + uprobe. + format: int64 + type: integer + pid: + description: |- + Only execute uprobe for given process identification number (PID). If PID + is not provided, uprobe executes for all PIDs. + format: int32 + type: integer + retprobe: + default: false + description: Whether the program is a uretprobe. Default is + false + type: boolean + target: + description: Library name or the absolute path to a binary or + library. + type: string + required: + - containers + - target + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -119,76 +221,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the uprobe. - If Containers is not specified, the uprobe will be attached in the - bpfman-agent container. The ContainerNsSelector is very flexible and even - allows the selection of all containers in a cluster. If an attempt is - made to attach uprobes to too many containers, it can have a negative - impact on on the cluster. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - func_name: - description: Function to attach the uprobe to. - type: string globaldata: additionalProperties: format: byte @@ -298,38 +330,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: Offset added to the address of the function for uprobe. - format: int64 - type: integer - pid: + oldmapownerselector: description: |- - Only execute uprobe for given process identification number (PID). If PID - is not provided, uprobe executes for all PIDs. - format: int32 - type: integer - retprobe: - default: false - description: Whether the program is a uretprobe. Default is false - type: boolean - target: - description: Library name or the absolute path to a binary or library. - type: string + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - containers - nodeselector - - target type: object status: - description: UprobeProgramStatus defines the observed state of UprobeProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_uprobeprograms.yaml b/bundle/manifests/bpfman.io_uprobeprograms.yaml index a3cdab8ad..81c5017c0 100644 --- a/bundle/manifests/bpfman.io_uprobeprograms.yaml +++ b/bundle/manifests/bpfman.io_uprobeprograms.yaml @@ -69,6 +69,111 @@ spec: spec: description: UprobeProgramSpec defines the desired state of UprobeProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the uprobe. + If Containers is not specified, the uprobe will be attached in the + bpfman-agent container. The ContainerSelector is very flexible and even + allows the selection of all containers in a cluster. If an attempt is + made to attach uprobes to too many containers, it can have a negative + impact on on the cluster. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + func_name: + description: Function to attach the uprobe to. + type: string + offset: + default: 0 + description: Offset added to the address of the function for + uprobe. + format: int64 + type: integer + pid: + description: |- + Only execute uprobe for given process identification number (PID). If PID + is not provided, uprobe executes for all PIDs. + format: int32 + type: integer + retprobe: + default: false + description: Whether the program is a uretprobe. Default is + false + type: boolean + target: + description: Library name or the absolute path to a binary or + library. + type: string + required: + - target + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -119,80 +224,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the uprobe. - If Containers is not specified, the uprobe will be attached in the - bpfman-agent container. The ContainerSelector is very flexible and even - allows the selection of all containers in a cluster. If an attempt is - made to attach uprobes to too many containers, it can have a negative - impact on on the cluster. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - func_name: - description: Function to attach the uprobe to. - type: string globaldata: additionalProperties: format: byte @@ -302,37 +333,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: Offset added to the address of the function for uprobe. - format: int64 - type: integer - pid: + oldmapownerselector: description: |- - Only execute uprobe for given process identification number (PID). If PID - is not provided, uprobe executes for all PIDs. - format: int32 - type: integer - retprobe: - default: false - description: Whether the program is a uretprobe. Default is false - type: boolean - target: - description: Library name or the absolute path to a binary or library. - type: string + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - nodeselector - - target type: object status: - description: UprobeProgramStatus defines the observed state of UprobeProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_xdpnsprograms.yaml b/bundle/manifests/bpfman.io_xdpnsprograms.yaml index 1b72eba49..88c25c37d 100644 --- a/bundle/manifests/bpfman.io_xdpnsprograms.yaml +++ b/bundle/manifests/bpfman.io_xdpnsprograms.yaml @@ -61,6 +61,126 @@ spec: spec: description: XdpNsProgramSpec defines the desired state of XdpNsProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + interfaceselector: + description: Selector to determine the network interface (or + interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary interface + on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the bpf program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pass + - dispatcher_return + description: |- + ProceedOn allows the user to call other xdp programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + required: + - containers + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -111,69 +231,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the eBPF - program. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object globaldata: additionalProperties: format: byte @@ -184,23 +241,6 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object - interfaceselector: - description: Selector to determine the network interface (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface on the - node. Only 'true' accepted. - type: boolean - type: object mapownerselector: description: |- MapOwnerSelector is used to select the loaded eBPF program this eBPF program @@ -300,48 +340,73 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: + oldmapownerselector: description: |- - Priority specifies the priority of the bpf program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pass - - dispatcher_return - description: |- - ProceedOn allows the user to call other xdp programs in chain on this exit code. - Multiple values are supported by repeating the parameter. - items: - enum: - - aborted - - drop - - pass - - tx - - redirect - - dispatcher_return - type: string - maxItems: 6 - type: array + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - containers - - interfaceselector - nodeselector - - priority type: object status: description: XdpProgramStatus defines the observed state of XdpProgram properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/bundle/manifests/bpfman.io_xdpprograms.yaml b/bundle/manifests/bpfman.io_xdpprograms.yaml index f55582862..498fc08b2 100644 --- a/bundle/manifests/bpfman.io_xdpprograms.yaml +++ b/bundle/manifests/bpfman.io_xdpprograms.yaml @@ -32,6 +32,10 @@ spec: name: InterfaceSelector priority: 1 type: string + - jsonPath: .spec.position + name: Position + priority: 1 + type: string - jsonPath: .spec.proceedon name: ProceedOn priority: 1 @@ -61,6 +65,130 @@ spec: spec: description: XdpProgramSpec defines the desired state of XdpProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + interfaceselector: + description: Selector to determine the network interface (or + interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary interface + on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the bpf program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pass + - dispatcher_return + description: |- + ProceedOn allows the user to call other xdp programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + required: + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -111,74 +239,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object globaldata: additionalProperties: format: byte @@ -189,23 +249,6 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object - interfaceselector: - description: Selector to determine the network interface (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface on the - node. Only 'true' accepted. - type: boolean - type: object mapownerselector: description: |- MapOwnerSelector is used to select the loaded eBPF program this eBPF program @@ -305,44 +348,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: + oldmapownerselector: description: |- - Priority specifies the priority of the bpf program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pass - - dispatcher_return - items: - enum: - - aborted - - drop - - pass - - tx - - redirect - - dispatcher_return - type: string - maxItems: 6 - type: array + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - interfaceselector - nodeselector - - priority type: object status: - description: XdpProgramStatus defines the observed state of XdpProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/cmd/bpfman-agent/main.go b/cmd/bpfman-agent/main.go index daaca165c..6fd6d5b6f 100644 --- a/cmd/bpfman-agent/main.go +++ b/cmd/bpfman-agent/main.go @@ -24,7 +24,8 @@ import ( "os" bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" - bpfmanagent "github.com/bpfman/bpfman-operator/controllers/bpfman-agent" + appagent "github.com/bpfman/bpfman-operator/controllers/app-agent" + //bpfmanagent "github.com/bpfman/bpfman-operator/controllers/bpfman-agent" "github.com/bpfman/bpfman-operator/internal/conn" gobpfman "github.com/bpfman/bpfman/clients/gobpfman/v1" @@ -139,135 +140,153 @@ func main() { os.Exit(1) } - containerGetter, err := bpfmanagent.NewRealContainerGetter(nodeName) + // containerGetter, err := bpfmanagent.NewRealContainerGetter(nodeName) + // if err != nil { + // setupLog.Error(err, "unable to create containerGetter") + // os.Exit(1) + // } + + // common := bpfmanagent.ReconcilerCommon[bpfmaniov1alpha1.BpfProgram, bpfmaniov1alpha1.BpfProgramList]{ + // Client: mgr.GetClient(), + // Scheme: mgr.GetScheme(), + // GrpcConn: conn, + // BpfmanClient: gobpfman.NewBpfmanClient(conn), + // NodeName: nodeName, + // Containers: containerGetter, + // } + + // commonCluster := bpfmanagent.ClusterProgramReconciler{ + // ReconcilerCommon: common, + // } + + // commonNs := bpfmanagent.ReconcilerCommon[bpfmaniov1alpha1.BpfNsProgram, bpfmaniov1alpha1.BpfNsProgramList]{ + // Client: mgr.GetClient(), + // Scheme: mgr.GetScheme(), + // GrpcConn: conn, + // BpfmanClient: gobpfman.NewBpfmanClient(conn), + // NodeName: nodeName, + // Containers: containerGetter, + // } + + // commonNamespace := bpfmanagent.NamespaceProgramReconciler{ + // ReconcilerCommon: commonNs, + // } + + appContainerGetter, err := appagent.NewRealContainerGetter(nodeName) if err != nil { setupLog.Error(err, "unable to create containerGetter") os.Exit(1) } - common := bpfmanagent.ReconcilerCommon[bpfmaniov1alpha1.BpfProgram, bpfmaniov1alpha1.BpfProgramList]{ + commonApp := appagent.ReconcilerCommon{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), GrpcConn: conn, BpfmanClient: gobpfman.NewBpfmanClient(conn), NodeName: nodeName, - Containers: containerGetter, + Containers: appContainerGetter, } - commonCluster := bpfmanagent.ClusterProgramReconciler{ - ReconcilerCommon: common, - } - - commonNs := bpfmanagent.ReconcilerCommon[bpfmaniov1alpha1.BpfNsProgram, bpfmaniov1alpha1.BpfNsProgramList]{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - GrpcConn: conn, - BpfmanClient: gobpfman.NewBpfmanClient(conn), - NodeName: nodeName, - Containers: containerGetter, - } - - commonNamespace := bpfmanagent.NamespaceProgramReconciler{ - ReconcilerCommon: commonNs, - } - - if err = (&bpfmanagent.XdpProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create xdpProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanagent.TcProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create tcProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanagent.TcxProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create tcxProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanagent.TracepointProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create tracepointProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanagent.KprobeProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create kprobeProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanagent.UprobeProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create uprobeProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanagent.FentryProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create fentryProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanagent.FexitProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create fexitProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanagent.BpfApplicationReconciler{ - ClusterProgramReconciler: commonCluster, + // if err = (&bpfmanagent.XdpProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create xdpProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanagent.TcProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create tcProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanagent.TcxProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create tcxProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanagent.TracepointProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create tracepointProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanagent.KprobeProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create kprobeProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanagent.UprobeProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create uprobeProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanagent.FentryProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create fentryProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanagent.FexitProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create fexitProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanagent.BpfApplicationReconciler{ + // ClusterProgramReconciler: commonCluster, + if err = (&appagent.BpfApplicationReconciler{ + ReconcilerCommon: commonApp, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create BpfApplicationProgram controller", "controller", "BpfProgram") os.Exit(1) } - if err = (&bpfmanagent.TcNsProgramReconciler{ - NamespaceProgramReconciler: commonNamespace, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create tcNsProgram controller", "controller", "BpfNsProgram") - os.Exit(1) - } - - if err = (&bpfmanagent.TcxNsProgramReconciler{ - NamespaceProgramReconciler: commonNamespace, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create tcxNsProgram controller", "controller", "BpfNsProgram") - os.Exit(1) - } - - if err = (&bpfmanagent.UprobeNsProgramReconciler{ - NamespaceProgramReconciler: commonNamespace, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create uprobeNsProgram controller", "controller", "BpfNsProgram") - os.Exit(1) - } + // if err = (&bpfmanagent.TcNsProgramReconciler{ + // NamespaceProgramReconciler: commonNamespace, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create tcNsProgram controller", "controller", "BpfNsProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanagent.TcxNsProgramReconciler{ + // NamespaceProgramReconciler: commonNamespace, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create tcxNsProgram controller", "controller", "BpfNsProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanagent.UprobeNsProgramReconciler{ + // NamespaceProgramReconciler: commonNamespace, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create uprobeNsProgram controller", "controller", "BpfNsProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanagent.XdpNsProgramReconciler{ + // NamespaceProgramReconciler: commonNamespace, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create xdpNsProgram controller", "controller", "BpfNsProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanagent.BpfNsApplicationReconciler{ + // NamespaceProgramReconciler: commonNamespace, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create BpfNsApplicationProgram controller", "controller", "BpfNsProgram") + // os.Exit(1) + // } - if err = (&bpfmanagent.XdpNsProgramReconciler{ - NamespaceProgramReconciler: commonNamespace, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create xdpNsProgram controller", "controller", "BpfNsProgram") - os.Exit(1) - } - - if err = (&bpfmanagent.BpfNsApplicationReconciler{ - NamespaceProgramReconciler: commonNamespace, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create BpfNsApplicationProgram controller", "controller", "BpfNsProgram") - os.Exit(1) - } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/cmd/bpfman-operator/main.go b/cmd/bpfman-operator/main.go index 1b933de6e..ffff66d18 100644 --- a/cmd/bpfman-operator/main.go +++ b/cmd/bpfman-operator/main.go @@ -22,7 +22,9 @@ import ( "os" bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" - bpfmanoperator "github.com/bpfman/bpfman-operator/controllers/bpfman-operator" + appoperator "github.com/bpfman/bpfman-operator/controllers/app-operator" + + // bpfmanoperator "github.com/bpfman/bpfman-operator/controllers/bpfman-operator" "github.com/bpfman/bpfman-operator/internal" osv1 "github.com/openshift/api/security/v1" @@ -163,22 +165,31 @@ func main() { os.Exit(1) } - common := bpfmanoperator.ReconcilerCommon[bpfmaniov1alpha1.BpfProgram, bpfmaniov1alpha1.BpfProgramList]{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - } + // common := bpfmanoperator.ReconcilerCommon[bpfmaniov1alpha1.BpfProgram, bpfmaniov1alpha1.BpfProgramList]{ + // Client: mgr.GetClient(), + // Scheme: mgr.GetScheme(), + // } - commonCluster := bpfmanoperator.ClusterProgramReconciler{ - ReconcilerCommon: common, - } + // commonCluster := bpfmanoperator.ClusterProgramReconciler{ + // ReconcilerCommon: common, + // } + + // commonNs := bpfmanoperator.ReconcilerCommon[bpfmaniov1alpha1.BpfNsProgram, bpfmaniov1alpha1.BpfNsProgramList]{ + // Client: mgr.GetClient(), + // Scheme: mgr.GetScheme(), + // } - commonNs := bpfmanoperator.ReconcilerCommon[bpfmaniov1alpha1.BpfNsProgram, bpfmaniov1alpha1.BpfNsProgramList]{ + // commonNamespace := bpfmanoperator.NamespaceProgramReconciler{ + // ReconcilerCommon: commonNs, + // } + + commonApp := appoperator.ReconcilerCommon[bpfmaniov1alpha1.BpfApplicationState, bpfmaniov1alpha1.BpfApplicationStateList]{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), } - commonNamespace := bpfmanoperator.NamespaceProgramReconciler{ - ReconcilerCommon: commonNs, + commonClusterApp := appoperator.ClusterProgramReconciler{ + ReconcilerCommon: commonApp, } setupLog.Info("Discovering APIs") @@ -195,8 +206,8 @@ func main() { } - if err = (&bpfmanoperator.BpfmanConfigReconciler{ - ClusterProgramReconciler: commonCluster, + if err = (&appoperator.BpfmanConfigReconciler{ + ClusterProgramReconciler: commonClusterApp, BpfmanStandardDeployment: internal.BpfmanDaemonManifestPath, CsiDriverDeployment: internal.BpfmanCsiDriverPath, RestrictedSCC: internal.BpfmanRestrictedSCCPath, @@ -206,103 +217,104 @@ func main() { os.Exit(1) } - if err = (&bpfmanoperator.XdpProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create xdpProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanoperator.TcProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create tcProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanoperator.TcxProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create tcxProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanoperator.TracepointProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create tracepointProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanoperator.KprobeProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create kprobeProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanoperator.UprobeProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create uprobeProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanoperator.FentryProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create fentryProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanoperator.FexitProgramReconciler{ - ClusterProgramReconciler: commonCluster, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create fexitProgram controller", "controller", "BpfProgram") - os.Exit(1) - } - - if err = (&bpfmanoperator.BpfApplicationReconciler{ - ClusterProgramReconciler: commonCluster, + // if err = (&bpfmanoperator.XdpProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create xdpProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanoperator.TcProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create tcProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanoperator.TcxProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create tcxProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanoperator.TracepointProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create tracepointProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanoperator.KprobeProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create kprobeProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanoperator.UprobeProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create uprobeProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanoperator.FentryProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create fentryProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanoperator.FexitProgramReconciler{ + // ClusterProgramReconciler: commonCluster, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create fexitProgram controller", "controller", "BpfProgram") + // os.Exit(1) + // } + + if err = (&appoperator.BpfApplicationReconciler{ + ClusterProgramReconciler: commonClusterApp, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "BpfApplication") os.Exit(1) } - if err = (&bpfmanoperator.TcNsProgramReconciler{ - NamespaceProgramReconciler: commonNamespace, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create tcProgram controller", "controller", "BpfNsProgram") - os.Exit(1) - } - - if err = (&bpfmanoperator.TcxNsProgramReconciler{ - NamespaceProgramReconciler: commonNamespace, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create tcxNsProgram controller", "controller", "BpfNsProgram") - os.Exit(1) - } - - if err = (&bpfmanoperator.UprobeNsProgramReconciler{ - NamespaceProgramReconciler: commonNamespace, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create uprobeNsProgram controller", "controller", "BpfNsProgram") - os.Exit(1) - } + // if err = (&bpfmanoperator.TcNsProgramReconciler{ + // NamespaceProgramReconciler: commonNamespace, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create tcProgram controller", "controller", "BpfNsProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanoperator.TcxNsProgramReconciler{ + // NamespaceProgramReconciler: commonNamespace, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create tcxNsProgram controller", "controller", "BpfNsProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanoperator.UprobeNsProgramReconciler{ + // NamespaceProgramReconciler: commonNamespace, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create uprobeNsProgram controller", "controller", "BpfNsProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanoperator.XdpNsProgramReconciler{ + // NamespaceProgramReconciler: commonNamespace, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create xdpNsProgram controller", "controller", "BpfNsProgram") + // os.Exit(1) + // } + + // if err = (&bpfmanoperator.BpfNsApplicationReconciler{ + // NamespaceProgramReconciler: commonNamespace, + // }).SetupWithManager(mgr); err != nil { + // setupLog.Error(err, "unable to create controller", "controller", "BpfNsApplication") + // os.Exit(1) + // } - if err = (&bpfmanoperator.XdpNsProgramReconciler{ - NamespaceProgramReconciler: commonNamespace, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create xdpNsProgram controller", "controller", "BpfNsProgram") - os.Exit(1) - } - - if err = (&bpfmanoperator.BpfNsApplicationReconciler{ - NamespaceProgramReconciler: commonNamespace, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "BpfNsApplication") - os.Exit(1) - } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/config/bpfman-deployment/config.yaml b/config/bpfman-deployment/config.yaml index ac9177f76..fd9fdaa54 100644 --- a/config/bpfman-deployment/config.yaml +++ b/config/bpfman-deployment/config.yaml @@ -8,7 +8,7 @@ data: bpfman.agent.image: quay.io/bpfman/bpfman-agent:latest bpfman.image: quay.io/bpfman/bpfman:latest ## Can be set to "info", "debug", or "trace" - bpfman.agent.log.level: info + bpfman.agent.log.level: debug ## See https://docs.rs/env_logger/latest/env_logger/ for configuration options bpfman.log.level: info bpfman.agent.healthprobe.addr: :8175 diff --git a/config/crd/bases/bpfman.io_bpfapplications.yaml b/config/crd/bases/bpfman.io_bpfapplications.yaml index da9ec0e06..e7b87d71e 100644 --- a/config/crd/bases/bpfman.io_bpfapplications.yaml +++ b/config/crd/bases/bpfman.io_bpfapplications.yaml @@ -104,6 +104,56 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object + mapownerselector: + description: |- + MapOwnerSelector is used to select the loaded eBPF program this eBPF program + will share a map with. The value is a label applied to the BpfProgram to select. + The selector must resolve to exactly one instance of a BpfProgram on a given node + or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic nodeselector: description: |- NodeSelector allows the user to specify which nodes to deploy the @@ -155,31 +205,45 @@ spec: x-kubernetes-map-type: atomic programs: description: |- - Programs is a list of bpf programs supported for a specific application. - It's possible that the application can selectively choose which program(s) - to run from this list. + Programs is the list of bpf programs in the BpfApplication that should be + loaded. The application can selectively choose which program(s) to run + from this list based on the optional attach points provided. items: description: BpfApplicationProgram defines the desired state of BpfApplication properties: + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string fentry: description: fentry defines the desired state of the application's FentryPrograms. properties: + attach: + description: Whether the bpf program should be attached + to the function. + type: boolean bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF program type: string - func_name: - description: Function to attach the fentry to. + function_name: + description: FunctionName is the name of the function to + attach the Fentry program to. type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -225,27 +289,35 @@ spec: type: object x-kubernetes-map-type: atomic required: + - attach - bpffunctionname - - func_name + - function_name type: object fexit: description: fexit defines the desired state of the application's FexitPrograms. properties: + attach: + type: boolean bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF program type: string - func_name: - description: Function to attach the fexit to. + function_name: + description: FunctionName is the name of the function to + attach the Fexit program to. type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -291,27 +363,57 @@ spec: type: object x-kubernetes-map-type: atomic required: + - attach - bpffunctionname - - func_name + - function_name type: object kprobe: description: kprobe defines the desired state of the application's KprobePrograms. properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + func_name: + description: Functions to attach the kprobe to. + type: string + offset: + default: 0 + description: |- + Offset added to the address of the function for kprobe. + Not allowed for kretprobes. + format: int64 + type: integer + retprobe: + default: false + description: Whether the program is a kretprobe. Default + is false + type: boolean + required: + - func_name + type: object + x-kubernetes-validations: + - message: offset cannot be set for kretprobes + rule: self.retprobe == false || self.offset == 0 + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF program type: string - func_name: - description: Functions to attach the kprobe to. - type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -356,40 +458,56 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: |- - Offset added to the address of the function for kprobe. - Not allowed for kretprobes. - format: int64 - type: integer - retprobe: - default: false - description: Whether the program is a kretprobe. Default - is false - type: boolean required: - bpffunctionname - - func_name type: object kretprobe: description: kretprobe defines the desired state of the application's KretprobePrograms. properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + func_name: + description: Functions to attach the kprobe to. + type: string + offset: + default: 0 + description: |- + Offset added to the address of the function for kprobe. + Not allowed for kretprobes. + format: int64 + type: integer + retprobe: + default: false + description: Whether the program is a kretprobe. Default + is false + type: boolean + required: + - func_name + type: object + x-kubernetes-validations: + - message: offset cannot be set for kretprobes + rule: self.retprobe == false || self.offset == 0 + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF program type: string - func_name: - description: Functions to attach the kprobe to. - type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -434,131 +552,221 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: |- - Offset added to the address of the function for kprobe. - Not allowed for kretprobes. - format: int64 - type: integer - retprobe: - default: false - description: Whether the program is a kretprobe. Default - is false - type: boolean required: - bpffunctionname - - func_name type: object + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic tc: description: tc defines the desired state of the application's TcPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tc program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pipe + - dispatcher_return + description: |- + ProceedOn allows the user to call other tc programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - unspec + - ok + - reclassify + - shot + - pipe + - stolen + - queued + - repeat + - redirect + - trap + - dispatcher_return + type: string + maxItems: 11 + type: array + required: + - direction + - interfaceselector + - priority + type: object + type: array + bpffunctionname: description: |- - Direction specifies the direction of traffic the tc program should - attach to for a given network device. - enum: - - ingress - - egress + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - interfaceselector: - description: Selector to determine the network interface - (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface - on the node. Only 'true' accepted. - type: boolean - type: object - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -603,153 +811,144 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pipe - - dispatcher_return - description: |- - ProceedOn allows the user to call other tc programs in chain on this exit code. - Multiple values are supported by repeating the parameter. - items: - enum: - - unspec - - ok - - reclassify - - shot - - pipe - - stolen - - queued - - repeat - - redirect - - trap - - dispatcher_return - type: string - maxItems: 11 - type: array required: - bpffunctionname - - direction - - interfaceselector - - priority type: object tcx: description: tcx defines the desired state of the application's TcxPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tcx program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tcx program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + required: + - direction + - interfaceselector + - priority + type: object + type: array + bpffunctionname: description: |- - Direction specifies the direction of traffic the tcx program should - attach to for a given network device. - enum: - - ingress - - egress + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - interfaceselector: - description: Selector to determine the network interface - (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface - on the node. Only 'true' accepted. - type: boolean - type: object - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -794,36 +993,43 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer required: - bpffunctionname - - direction - - interfaceselector - - priority type: object tracepoint: description: tracepoint defines the desired state of the application's TracepointPrograms. properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + name: + description: |- + Name refers to the name of a kernel tracepoint to attach the + bpf program to. + type: string + required: + - name + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF program type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -868,16 +1074,8 @@ spec: type: object type: object x-kubernetes-map-type: atomic - names: - description: |- - Names refers to the names of kernel tracepoints to attach the - bpf program to. - items: - type: string - type: array required: - bpffunctionname - - names type: object type: description: Type specifies the bpf program type @@ -897,91 +1095,127 @@ spec: description: uprobe defines the desired state of the application's UprobePrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the uprobe. - If Containers is not specified, the uprobe will be attached in the - bpfman-agent container. The ContainerSelector is very flexible and even - allows the selection of all containers in a cluster. If an attempt is - made to attach uprobes to too many containers, it can have a negative - impact on on the cluster. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the uprobe. + If Containers is not specified, the uprobe will be attached in the + bpfman-agent container. The ContainerSelector is very flexible and even + allows the selection of all containers in a cluster. If an attempt is + made to attach uprobes to too many containers, it can have a negative + impact on on the cluster. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - func_name: - description: Function to attach the uprobe to. + x-kubernetes-map-type: atomic + required: + - pods + type: object + func_name: + description: Function to attach the uprobe to. + type: string + offset: + default: 0 + description: Offset added to the address of the function + for uprobe. + format: int64 + type: integer + pid: + description: |- + Only execute uprobe for given process identification number (PID). If PID + is not provided, uprobe executes for all PIDs. + format: int32 + type: integer + retprobe: + default: false + description: Whether the program is a uretprobe. Default + is false + type: boolean + target: + description: Library name or the absolute path to + a binary or library. + type: string + required: + - target + type: object + type: array + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -1026,120 +1260,134 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: Offset added to the address of the function - for uprobe. - format: int64 - type: integer - pid: - description: |- - Only execute uprobe for given process identification number (PID). If PID - is not provided, uprobe executes for all PIDs. - format: int32 - type: integer - retprobe: - default: false - description: Whether the program is a uretprobe. Default - is false - type: boolean - target: - description: Library name or the absolute path to a binary - or library. - type: string required: - bpffunctionname - - target type: object uretprobe: description: uretprobe defines the desired state of the application's UretprobePrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the uprobe. - If Containers is not specified, the uprobe will be attached in the - bpfman-agent container. The ContainerSelector is very flexible and even - allows the selection of all containers in a cluster. If an attempt is - made to attach uprobes to too many containers, it can have a negative - impact on on the cluster. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the uprobe. + If Containers is not specified, the uprobe will be attached in the + bpfman-agent container. The ContainerSelector is very flexible and even + allows the selection of all containers in a cluster. If an attempt is + made to attach uprobes to too many containers, it can have a negative + impact on on the cluster. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - func_name: - description: Function to attach the uprobe to. + x-kubernetes-map-type: atomic + required: + - pods + type: object + func_name: + description: Function to attach the uprobe to. + type: string + offset: + default: 0 + description: Offset added to the address of the function + for uprobe. + format: int64 + type: integer + pid: + description: |- + Only execute uprobe for given process identification number (PID). If PID + is not provided, uprobe executes for all PIDs. + format: int32 + type: integer + retprobe: + default: false + description: Whether the program is a uretprobe. Default + is false + type: boolean + target: + description: Library name or the absolute path to + a binary or library. + type: string + required: + - target + type: object + type: array + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -1184,132 +1432,153 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: Offset added to the address of the function - for uprobe. - format: int64 - type: integer - pid: - description: |- - Only execute uprobe for given process identification number (PID). If PID - is not provided, uprobe executes for all PIDs. - format: int32 - type: integer - retprobe: - default: false - description: Whether the program is a uretprobe. Default - is false - type: boolean - target: - description: Library name or the absolute path to a binary - or library. - type: string required: - bpffunctionname - - target type: object xdp: description: xdp defines the desired state of the application's XdpPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - interfaceselector: - description: Selector to determine the network interface - (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface - on the node. Only 'true' accepted. - type: boolean - type: object - mapownerselector: + x-kubernetes-map-type: atomic + required: + - pods + type: object + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the bpf program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pass + - dispatcher_return + description: |- + ProceedOn allows the user to call other xdp programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + required: + - interfaceselector + - priority + type: object + type: array + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -1354,35 +1623,11 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the bpf program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pass - - dispatcher_return - items: - enum: - - aborted - - drop - - pass - - tx - - redirect - - dispatcher_return - type: string - maxItems: 6 - type: array required: - bpffunctionname - - interfaceselector - - priority type: object + required: + - bpffunctionname type: object x-kubernetes-validations: - message: xdp configuration is required when type is XDP, and forbidden @@ -1425,19 +1670,20 @@ spec: and forbidden otherwise rule: 'has(self.type) && self.type == ''Tracepoint'' ? has(self.tracepoint) : !has(self.tracepoint)' - minItems: 1 type: array required: - bytecode - nodeselector type: object status: - description: BpfApplicationStatus defines the observed state of BpfApplication + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_bpfapplicationstates.yaml b/config/crd/bases/bpfman.io_bpfapplicationstates.yaml new file mode 100644 index 000000000..81fbe5f3e --- /dev/null +++ b/config/crd/bases/bpfman.io_bpfapplicationstates.yaml @@ -0,0 +1,634 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: bpfapplicationstates.bpfman.io +spec: + group: bpfman.io + names: + kind: BpfApplicationState + listKind: BpfApplicationStateList + plural: bpfapplicationstates + singular: bpfapplicationstate + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.node + name: Node + type: string + - jsonPath: .status.conditions[0].reason + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + BpfApplicationState contains the per-node state of a BpfApplication. + ANF-TODO: I can't get the Node to display in the kubectl output. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: BpfApplicationSpec defines the desired state of BpfApplication + properties: + apploadstatus: + description: |- + AppLoadStatus reflects the status of loading the bpf application on the + given node. + type: string + node: + description: Node is the name of the node for this BpfApplicationStateSpec. + type: string + programs: + description: |- + Programs is a list of bpf programs contained in the parent application. + It is a map from the bpf program name to BpfApplicationProgramState + elements. + items: + description: |- + BpfApplicationProgramState defines the desired state of BpfApplication + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'TC' ? has(self.tc) : !has(self.tc)",message="tc configuration is required when type is TC, and forbidden otherwise" + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Fexit' ? has(self.fexit) : !has(self.fexit)",message="fexit configuration is required when type is Fexit, and forbidden otherwise" + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Kprobe' ? has(self.kprobe) : !has(self.kprobe)",message="kprobe configuration is required when type is Kprobe, and forbidden otherwise" + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Kretprobe' ? has(self.kretprobe) : !has(self.kretprobe)",message="kretprobe configuration is required when type is Kretprobe, and forbidden otherwise" + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Uprobe' ? has(self.uprobe) : !has(self.uprobe)",message="uprobe configuration is required when type is Uprobe, and forbidden otherwise" + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Uretprobe' ? has(self.uretprobe) : !has(self.uretprobe)",message="uretprobe configuration is required when type is Uretprobe, and forbidden otherwise" + // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Tracepoint' ? has(self.tracepoint) : !has(self.tracepoint)",message="tracepoint configuration is required when type is Tracepoint, and forbidden otherwise" + properties: + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + fentry: + description: fentry defines the desired state of the application's + FentryPrograms. + properties: + attach: + type: boolean + attachid: + description: |- + An identifier for the attach point assigned by bpfman. This field is + empty until the program is successfully attached and bpfman returns the + id. + ANF-TODO: For the POC, this will be the program ID. + format: int32 + type: integer + attachstatus: + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. + type: string + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + function_name: + description: FunctionName is the name of the function to + attach the Fentry program to. + type: string + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + program_id: + description: |- + ProgramId is the id of the program in the kernel. Not set until the + program is loaded. + format: int32 + type: integer + programattachstatus: + description: |- + ProgramAttachStatus records whether the program should be loaded and whether + the program is loaded. + type: string + should_attach: + description: ShouldAttach reflects whether the attachment + should exist. + type: boolean + uuid: + description: |- + ANF-TODO: Putting a uuid here for now to maintain compatibility with the + existing BpfProgram. + type: string + required: + - attach + - attachid + - attachstatus + - bpffunctionname + - function_name + - programattachstatus + - should_attach + - uuid + type: object + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + program_id: + description: |- + ProgramId is the id of the program in the kernel. Not set until the + program is loaded. + format: int32 + type: integer + programattachstatus: + description: |- + ProgramAttachStatus records whether the program should be loaded and whether + the program is loaded. + type: string + tc: + description: tc defines the desired state of the application's + TcPrograms. + properties: + attach_points: + description: |- + The list of points to which the program should be attached. + TcAttachInfoState is similar to TcAttachInfo, but the interface and + container selectors are expanded, and we have one instance of + TcAttachInfoState for each unique attach point. The list is optional and + may be udated after the bpf program has been loaded. + items: + properties: + attachid: + description: |- + An identifier for the attach point assigned by bpfman. This field is + empty until the program is successfully attached and bpfman returns the + id. + ANF-TODO: For the POC, this will be the program ID. + format: int32 + type: integer + attachstatus: + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. + type: string + containerpid: + description: Optional container pid to attach the + tc program in. + format: int32 + type: integer + direction: + description: |- + Direction specifies the direction of traffic the tc program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + ifname: + description: Interface name to attach the tc program + to. + type: string + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + description: |- + ProceedOn allows the user to call other tc programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - unspec + - ok + - reclassify + - shot + - pipe + - stolen + - queued + - repeat + - redirect + - trap + - dispatcher_return + type: string + maxItems: 11 + type: array + should_attach: + description: ShouldAttach reflects whether the attachment + should exist. + type: boolean + uuid: + description: |- + ANF-TODO: Putting a uuid here for now to maintain compatibility with the + existing BpfProgram. + type: string + required: + - attachid + - attachstatus + - direction + - ifname + - priority + - proceedon + - should_attach + - uuid + type: object + type: array + type: object + tcx: + description: tcx defines the desired state of the application's + TcxPrograms. + properties: + attach_points: + description: |- + The list of points to which the program should be attached. + TcxAttachInfoState is similar to TcxAttachInfo, but the interface and + container selectors are expanded, and we have one instance of + TcxAttachInfoState for each unique attach point. The list is optional and + may be udated after the bpf program has been loaded. + items: + properties: + attachid: + description: |- + An identifier for the attach point assigned by bpfman. This field is + empty until the program is successfully attached and bpfman returns the + id. + ANF-TODO: For the POC, this will be the program ID. + format: int32 + type: integer + attachstatus: + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. + type: string + containerpid: + description: Optional container pid to attach the + tcx program in. + format: int32 + type: integer + direction: + description: |- + Direction specifies the direction of traffic the tcx program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + ifname: + description: Interface name to attach the tcx program + to. + type: string + priority: + description: |- + Priority specifies the priority of the tcx program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + should_attach: + description: ShouldAttach reflects whether the attachment + should exist. + type: boolean + uuid: + description: |- + ANF-TODO: Putting a uuid here for now to maintain compatibility with the + existing BpfProgram. + type: string + required: + - attachid + - attachstatus + - direction + - ifname + - priority + - should_attach + - uuid + type: object + type: array + type: object + type: + description: Type specifies the bpf program type + enum: + - XDP + - TC + - TCX + - Fentry + - Fexit + - Kprobe + - Kretprobe + - Uprobe + - Uretprobe + - Tracepoint + type: string + xdp: + description: xdp defines the desired state of the application's + XdpPrograms. + properties: + attach_points: + description: |- + The list of points to which the program should be attached. + XdpAttachInfoState is similar to XdpAttachInfo, but the interface and + container selectors are expanded, and we have one instance of + XdpAttachInfoState for each unique attach point. The list is optional and + may be udated after the bpf program has been loaded. + items: + properties: + attachid: + description: |- + An identifier for the attach point assigned by bpfman. This field is + empty until the program is successfully attached and bpfman returns the + id. + ANF-TODO: For the POC, this will be the program ID. + format: int32 + type: integer + attachstatus: + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. + type: string + containerpid: + description: Optional container pid to attach the + xdp program in. + format: int32 + type: integer + ifname: + description: Interface name to attach the xdp program + to. + type: string + priority: + description: |- + Priority specifies the priority of the xdp program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + description: |- + ProceedOn allows the user to call other xdp programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + should_attach: + description: ShouldAttach reflects whether the attachment + should exist. + type: boolean + uuid: + description: |- + ANF-TODO: Putting a uuid here for now to maintain compatibility with the + existing BpfProgram. + type: string + required: + - attachid + - attachstatus + - ifname + - priority + - proceedon + - should_attach + - uuid + type: object + type: array + type: object + required: + - bpffunctionname + - programattachstatus + type: object + x-kubernetes-validations: + - message: xdp configuration is required when type is XDP, and forbidden + otherwise + rule: 'has(self.type) && self.type == ''XDP'' ? has(self.xdp) + : !has(self.xdp)' + - message: tcx configuration is required when type is TCX, and forbidden + otherwise + rule: 'has(self.type) && self.type == ''TCX'' ? has(self.tcx) + : !has(self.tcx)' + - message: fentry configuration is required when type is Fentry, + and forbidden otherwise + rule: 'has(self.type) && self.type == ''Fentry'' ? has(self.fentry) + : !has(self.fentry)' + type: array + updatecount: + description: |- + The number of times the BpfApplicationState has been updated. Set to 1 + when the object is created, then it is incremented prior to each update. + This allows us to verify that the API server has the updated object prior + to starting a new Reconcile operation. + format: int64 + type: integer + required: + - apploadstatus + - node + - updatecount + type: object + status: + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object + properties: + conditions: + description: |- + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/bpfman.io_bpfnsapplications.yaml b/config/crd/bases/bpfman.io_bpfnsapplications.yaml index 403eaf2e2..172ebd916 100644 --- a/config/crd/bases/bpfman.io_bpfnsapplications.yaml +++ b/config/crd/bases/bpfman.io_bpfnsapplications.yaml @@ -104,6 +104,56 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object + mapownerselector: + description: |- + MapOwnerSelector is used to select the loaded eBPF program this eBPF program + will share a map with. The value is a label applied to the BpfProgram to select. + The selector must resolve to exactly one instance of a BpfProgram on a given node + or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic nodeselector: description: |- NodeSelector allows the user to specify which nodes to deploy the @@ -166,106 +216,156 @@ spec: description: tc defines the desired state of the application's TcNsPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. + properties: + containernames: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tc program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pipe + - dispatcher_return + description: |- + ProceedOn allows the user to call other tc programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - unspec + - ok + - reclassify + - shot + - pipe + - stolen + - queued + - repeat + - redirect + - trap + - dispatcher_return + type: string + maxItems: 11 + type: array + required: + - containers + - direction + - interfaceselector + - priority + type: object + type: array + bpffunctionname: description: |- - Direction specifies the direction of traffic the tc program should - attach to for a given network device. - enum: - - ingress - - egress + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - interfaceselector: - description: Selector to determine the network interface - (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface - on the node. Only 'true' accepted. - type: boolean - type: object - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -310,149 +410,141 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pipe - - dispatcher_return - description: |- - ProceedOn allows the user to call other tc programs in chain on this exit code. - Multiple values are supported by repeating the parameter. - items: - enum: - - unspec - - ok - - reclassify - - shot - - pipe - - stolen - - queued - - repeat - - redirect - - trap - - dispatcher_return - type: string - maxItems: 11 - type: array required: - bpffunctionname - - containers - - direction - - interfaceselector - - priority type: object tcx: description: tcx defines the desired state of the application's TcxNsPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tcx program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + required: + - containers + - direction + - interfaceselector + - priority + type: object + type: array + bpffunctionname: description: |- - Direction specifies the direction of traffic the tcx program should - attach to for a given network device. - enum: - - ingress - - egress + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - interfaceselector: - description: Selector to determine the network interface - (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface - on the node. Only 'true' accepted. - type: boolean - type: object - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -497,21 +589,8 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer required: - bpffunctionname - - containers - - direction - - interfaceselector - - priority type: object type: description: Type specifies the bpf program type @@ -526,87 +605,124 @@ spec: description: uprobe defines the desired state of the application's UprobeNsPrograms. properties: - bpffunctionname: + attach_points: description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: - description: |- - Containers identifies the set of containers in which to attach the uprobe. - If Containers is not specified, the uprobe will be attached in the - bpfman-agent container. The ContainerNsSelector is very flexible and even - allows the selection of all containers in a cluster. If an attempt is - made to attach uprobes to too many containers, it can have a negative - impact on on the cluster. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the uprobe. + If Containers is not specified, the uprobe will be attached in the + bpfman-agent container. The ContainerNsSelector is very flexible and even + allows the selection of all containers in a cluster. If an attempt is + made to attach uprobes to too many containers, it can have a negative + impact on on the cluster. + properties: + containernames: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - func_name: - description: Function to attach the uprobe to. + x-kubernetes-map-type: atomic + required: + - pods + type: object + func_name: + description: Function to attach the uprobe to. + type: string + offset: + default: 0 + description: Offset added to the address of the function + for uprobe. + format: int64 + type: integer + pid: + description: |- + Only execute uprobe for given process identification number (PID). If PID + is not provided, uprobe executes for all PIDs. + format: int32 + type: integer + retprobe: + default: false + description: Whether the program is a uretprobe. Default + is false + type: boolean + target: + description: Library name or the absolute path to + a binary or library. + type: string + required: + - containers + - target + type: object + type: array + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -651,117 +767,131 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: Offset added to the address of the function - for uprobe. - format: int64 - type: integer - pid: - description: |- - Only execute uprobe for given process identification number (PID). If PID - is not provided, uprobe executes for all PIDs. - format: int32 - type: integer - retprobe: - default: false - description: Whether the program is a uretprobe. Default - is false - type: boolean - target: - description: Library name or the absolute path to a binary - or library. - type: string required: - bpffunctionname - - containers - - target type: object uretprobe: description: uretprobe defines the desired state of the application's UretprobeNsPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the uprobe. - If Containers is not specified, the uprobe will be attached in the - bpfman-agent container. The ContainerNsSelector is very flexible and even - allows the selection of all containers in a cluster. If an attempt is - made to attach uprobes to too many containers, it can have a negative - impact on on the cluster. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the uprobe. + If Containers is not specified, the uprobe will be attached in the + bpfman-agent container. The ContainerNsSelector is very flexible and even + allows the selection of all containers in a cluster. If an attempt is + made to attach uprobes to too many containers, it can have a negative + impact on on the cluster. + properties: + containernames: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - func_name: - description: Function to attach the uprobe to. + x-kubernetes-map-type: atomic + required: + - pods + type: object + func_name: + description: Function to attach the uprobe to. + type: string + offset: + default: 0 + description: Offset added to the address of the function + for uprobe. + format: int64 + type: integer + pid: + description: |- + Only execute uprobe for given process identification number (PID). If PID + is not provided, uprobe executes for all PIDs. + format: int32 + type: integer + retprobe: + default: false + description: Whether the program is a uretprobe. Default + is false + type: boolean + target: + description: Library name or the absolute path to + a binary or library. + type: string + required: + - containers + - target + type: object + type: array + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program type: string - mapownerselector: + oldmapownerselector: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -806,128 +936,149 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: Offset added to the address of the function - for uprobe. - format: int64 - type: integer - pid: - description: |- - Only execute uprobe for given process identification number (PID). If PID - is not provided, uprobe executes for all PIDs. - format: int32 - type: integer - retprobe: - default: false - description: Whether the program is a uretprobe. Default - is false - type: boolean - target: - description: Library name or the absolute path to a binary - or library. - type: string required: - bpffunctionname - - containers - - target type: object xdp: description: xdp defines the desired state of the application's XdpNsPrograms. properties: - bpffunctionname: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - interfaceselector: - description: Selector to determine the network interface - (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface - on the node. Only 'true' accepted. - type: boolean - type: object - mapownerselector: + x-kubernetes-map-type: atomic + required: + - pods + type: object + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the bpf program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pass + - dispatcher_return + description: |- + ProceedOn allows the user to call other xdp programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + required: + - containers + - interfaceselector + - priority + type: object + type: array + bpffunctionname: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program - will share a map with. The value is a label applied to the BpfProgram to select. - The selector must resolve to exactly one instance of a BpfProgram on a given node - or the eBPF program will not load. + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -972,38 +1123,8 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the bpf program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pass - - dispatcher_return - description: |- - ProceedOn allows the user to call other xdp programs in chain on this exit code. - Multiple values are supported by repeating the parameter. - items: - enum: - - aborted - - drop - - pass - - tx - - redirect - - dispatcher_return - type: string - maxItems: 6 - type: array required: - bpffunctionname - - containers - - interfaceselector - - priority type: object type: object x-kubernetes-validations: @@ -1034,12 +1155,14 @@ spec: - nodeselector type: object status: - description: BpfApplicationStatus defines the observed state of BpfApplication + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_fentryprograms.yaml b/config/crd/bases/bpfman.io_fentryprograms.yaml index 129fecf6f..c88eb22e4 100644 --- a/config/crd/bases/bpfman.io_fentryprograms.yaml +++ b/config/crd/bases/bpfman.io_fentryprograms.yaml @@ -53,6 +53,9 @@ spec: spec: description: FentryProgramSpec defines the desired state of FentryProgram properties: + attach: + description: Whether the bpf program should be attached to the function. + type: boolean bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -103,8 +106,9 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - func_name: - description: Function to attach the fentry to. + function_name: + description: FunctionName is the name of the function to attach the + Fentry program to. type: string globaldata: additionalProperties: @@ -215,19 +219,76 @@ spec: type: object type: object x-kubernetes-map-type: atomic + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: + - attach - bpffunctionname - bytecode - - func_name + - function_name - nodeselector type: object status: - description: FentryProgramStatus defines the observed state of FentryProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_fexitprograms.yaml b/config/crd/bases/bpfman.io_fexitprograms.yaml index d8e8bbd51..f72982f0d 100644 --- a/config/crd/bases/bpfman.io_fexitprograms.yaml +++ b/config/crd/bases/bpfman.io_fexitprograms.yaml @@ -53,6 +53,8 @@ spec: spec: description: FexitProgramSpec defines the desired state of FexitProgram properties: + attach: + type: boolean bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -103,8 +105,9 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - func_name: - description: Function to attach the fexit to. + function_name: + description: FunctionName is the name of the function to attach the + Fexit program to. type: string globaldata: additionalProperties: @@ -215,19 +218,76 @@ spec: type: object type: object x-kubernetes-map-type: atomic + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: + - attach - bpffunctionname - bytecode - - func_name + - function_name - nodeselector type: object status: - description: FexitProgramStatus defines the observed state of FexitProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_kprobeprograms.yaml b/config/crd/bases/bpfman.io_kprobeprograms.yaml index 076d269e5..ee4f9ee99 100644 --- a/config/crd/bases/bpfman.io_kprobeprograms.yaml +++ b/config/crd/bases/bpfman.io_kprobeprograms.yaml @@ -61,6 +61,34 @@ spec: spec: description: KprobeProgramSpec defines the desired state of KprobeProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + func_name: + description: Functions to attach the kprobe to. + type: string + offset: + default: 0 + description: |- + Offset added to the address of the function for kprobe. + Not allowed for kretprobes. + format: int64 + type: integer + retprobe: + default: false + description: Whether the program is a kretprobe. Default is + false + type: boolean + required: + - func_name + type: object + x-kubernetes-validations: + - message: offset cannot be set for kretprobes + rule: self.retprobe == false || self.offset == 0 + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -111,9 +139,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - func_name: - description: Functions to attach the kprobe to. - type: string globaldata: additionalProperties: format: byte @@ -223,33 +248,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 + oldmapownerselector: description: |- - Offset added to the address of the function for kprobe. - Not allowed for kretprobes. - format: int64 - type: integer - retprobe: - default: false - description: Whether the program is a kretprobe. Default is false - type: boolean + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - func_name - nodeselector type: object - x-kubernetes-validations: - - message: offset cannot be set for kretprobes - rule: self.retprobe == false || self.offset == 0 status: - description: KprobeProgramStatus defines the observed state of KprobeProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_tcnsprograms.yaml b/config/crd/bases/bpfman.io_tcnsprograms.yaml index 12a633c45..e5e84bd5e 100644 --- a/config/crd/bases/bpfman.io_tcnsprograms.yaml +++ b/config/crd/bases/bpfman.io_tcnsprograms.yaml @@ -65,6 +65,140 @@ spec: spec: description: TcNsProgramSpec defines the desired state of TcNsProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tc program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface (or + interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary interface + on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pipe + - dispatcher_return + description: |- + ProceedOn allows the user to call other tc programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - unspec + - ok + - reclassify + - shot + - pipe + - stolen + - queued + - repeat + - redirect + - trap + - dispatcher_return + type: string + maxItems: 11 + type: array + required: + - containers + - direction + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -115,77 +249,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the eBPF - program. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: - description: |- - Direction specifies the direction of traffic the tc program should - attach to for a given network device. - enum: - - ingress - - egress - type: string globaldata: additionalProperties: format: byte @@ -196,23 +259,6 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object - interfaceselector: - description: Selector to determine the network interface (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface on the - node. Only 'true' accepted. - type: boolean - type: object mapownerselector: description: |- MapOwnerSelector is used to select the loaded eBPF program this eBPF program @@ -312,54 +358,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: - description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pipe - - dispatcher_return + oldmapownerselector: description: |- - ProceedOn allows the user to call other tc programs in chain on this exit code. - Multiple values are supported by repeating the parameter. - items: - enum: - - unspec - - ok - - reclassify - - shot - - pipe - - stolen - - queued - - repeat - - redirect - - trap - - dispatcher_return - type: string - maxItems: 11 - type: array + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - containers - - direction - - interfaceselector - nodeselector - - priority type: object status: - description: TcProgramStatus defines the observed state of TcProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_tcprograms.yaml b/config/crd/bases/bpfman.io_tcprograms.yaml index fa56278c8..371c61f9b 100644 --- a/config/crd/bases/bpfman.io_tcprograms.yaml +++ b/config/crd/bases/bpfman.io_tcprograms.yaml @@ -65,6 +65,144 @@ spec: spec: description: TcProgramSpec defines the desired state of TcProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tc program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface (or + interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary interface + on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pipe + - dispatcher_return + description: |- + ProceedOn allows the user to call other tc programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - unspec + - ok + - reclassify + - shot + - pipe + - stolen + - queued + - repeat + - redirect + - trap + - dispatcher_return + type: string + maxItems: 11 + type: array + required: + - direction + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -115,82 +253,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: - description: |- - Direction specifies the direction of traffic the tc program should - attach to for a given network device. - enum: - - ingress - - egress - type: string globaldata: additionalProperties: format: byte @@ -201,23 +263,6 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object - interfaceselector: - description: Selector to determine the network interface (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface on the - node. Only 'true' accepted. - type: boolean - type: object mapownerselector: description: |- MapOwnerSelector is used to select the loaded eBPF program this eBPF program @@ -317,53 +362,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: + oldmapownerselector: description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pipe - - dispatcher_return - description: |- - ProceedOn allows the user to call other tc programs in chain on this exit code. - Multiple values are supported by repeating the parameter. - items: - enum: - - unspec - - ok - - reclassify - - shot - - pipe - - stolen - - queued - - repeat - - redirect - - trap - - dispatcher_return - type: string - maxItems: 11 - type: array + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - direction - - interfaceselector - nodeselector - - priority type: object status: - description: TcProgramStatus defines the observed state of TcProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_tcxnsprograms.yaml b/config/crd/bases/bpfman.io_tcxnsprograms.yaml index f7508f18e..7afb69adb 100644 --- a/config/crd/bases/bpfman.io_tcxnsprograms.yaml +++ b/config/crd/bases/bpfman.io_tcxnsprograms.yaml @@ -65,6 +65,118 @@ spec: spec: description: TcxNsProgramSpec defines the desired state of TcxNsProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tcx program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface (or + interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary interface + on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + required: + - containers + - direction + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -115,77 +227,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the eBPF - program. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: - description: |- - Direction specifies the direction of traffic the tcx program should - attach to for a given network device. - enum: - - ingress - - egress - type: string globaldata: additionalProperties: format: byte @@ -196,23 +237,6 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object - interfaceselector: - description: Selector to determine the network interface (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface on the - node. Only 'true' accepted. - type: boolean - type: object mapownerselector: description: |- MapOwnerSelector is used to select the loaded eBPF program this eBPF program @@ -312,31 +336,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: + oldmapownerselector: description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - containers - - direction - - interfaceselector - nodeselector - - priority type: object status: - description: TcxProgramStatus defines the observed state of TcxProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_tcxprograms.yaml b/config/crd/bases/bpfman.io_tcxprograms.yaml index bf97f8e41..22d26f1d6 100644 --- a/config/crd/bases/bpfman.io_tcxprograms.yaml +++ b/config/crd/bases/bpfman.io_tcxprograms.yaml @@ -24,6 +24,10 @@ spec: - jsonPath: .status.conditions[0].reason name: Status type: string + - jsonPath: .spec.priority + name: Priority + priority: 1 + type: string - jsonPath: .spec.direction name: Direction priority: 1 @@ -36,10 +40,6 @@ spec: name: Position priority: 1 type: string - - jsonPath: .spec.priority - name: Priority - priority: 1 - type: string name: v1alpha1 schema: openAPIV3Schema: @@ -65,6 +65,121 @@ spec: spec: description: TcxProgramSpec defines the desired state of TcxProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tcx program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface (or + interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary interface + on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the tcx program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + required: + - direction + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -115,82 +230,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: - description: |- - Direction specifies the direction of traffic the tcx program should - attach to for a given network device. - enum: - - ingress - - egress - type: string globaldata: additionalProperties: format: byte @@ -201,23 +240,6 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object - interfaceselector: - description: Selector to determine the network interface (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface on the - node. Only 'true' accepted. - type: boolean - type: object mapownerselector: description: |- MapOwnerSelector is used to select the loaded eBPF program this eBPF program @@ -317,30 +339,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: + oldmapownerselector: description: |- - Priority specifies the priority of the tc program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - direction - - interfaceselector - nodeselector - - priority type: object status: - description: TcxProgramStatus defines the observed state of TcxProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_tracepointprograms.yaml b/config/crd/bases/bpfman.io_tracepointprograms.yaml index bbcc48241..20aee0e47 100644 --- a/config/crd/bases/bpfman.io_tracepointprograms.yaml +++ b/config/crd/bases/bpfman.io_tracepointprograms.yaml @@ -53,6 +53,21 @@ spec: spec: description: TracepointProgramSpec defines the desired state of TracepointProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + name: + description: |- + Name refers to the name of a kernel tracepoint to attach the + bpf program to. + type: string + required: + - name + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -163,13 +178,6 @@ spec: type: object type: object x-kubernetes-map-type: atomic - names: - description: |- - Names refers to the names of kernel tracepoints to attach the - bpf program to. - items: - type: string - type: array nodeselector: description: |- NodeSelector allows the user to specify which nodes to deploy the @@ -219,19 +227,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic + oldmapownerselector: + description: |- + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - names - nodeselector type: object status: - description: TracepointProgramStatus defines the observed state of TracepointProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_uprobensprograms.yaml b/config/crd/bases/bpfman.io_uprobensprograms.yaml index 45be66c7d..8c4da41fd 100644 --- a/config/crd/bases/bpfman.io_uprobensprograms.yaml +++ b/config/crd/bases/bpfman.io_uprobensprograms.yaml @@ -69,6 +69,108 @@ spec: spec: description: UprobeNsProgramSpec defines the desired state of UprobeProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the uprobe. + If Containers is not specified, the uprobe will be attached in the + bpfman-agent container. The ContainerNsSelector is very flexible and even + allows the selection of all containers in a cluster. If an attempt is + made to attach uprobes to too many containers, it can have a negative + impact on on the cluster. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + func_name: + description: Function to attach the uprobe to. + type: string + offset: + default: 0 + description: Offset added to the address of the function for + uprobe. + format: int64 + type: integer + pid: + description: |- + Only execute uprobe for given process identification number (PID). If PID + is not provided, uprobe executes for all PIDs. + format: int32 + type: integer + retprobe: + default: false + description: Whether the program is a uretprobe. Default is + false + type: boolean + target: + description: Library name or the absolute path to a binary or + library. + type: string + required: + - containers + - target + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -119,76 +221,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the uprobe. - If Containers is not specified, the uprobe will be attached in the - bpfman-agent container. The ContainerNsSelector is very flexible and even - allows the selection of all containers in a cluster. If an attempt is - made to attach uprobes to too many containers, it can have a negative - impact on on the cluster. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - func_name: - description: Function to attach the uprobe to. - type: string globaldata: additionalProperties: format: byte @@ -298,38 +330,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: Offset added to the address of the function for uprobe. - format: int64 - type: integer - pid: + oldmapownerselector: description: |- - Only execute uprobe for given process identification number (PID). If PID - is not provided, uprobe executes for all PIDs. - format: int32 - type: integer - retprobe: - default: false - description: Whether the program is a uretprobe. Default is false - type: boolean - target: - description: Library name or the absolute path to a binary or library. - type: string + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - containers - nodeselector - - target type: object status: - description: UprobeProgramStatus defines the observed state of UprobeProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_uprobeprograms.yaml b/config/crd/bases/bpfman.io_uprobeprograms.yaml index 26e3daf9b..ccd1acced 100644 --- a/config/crd/bases/bpfman.io_uprobeprograms.yaml +++ b/config/crd/bases/bpfman.io_uprobeprograms.yaml @@ -69,6 +69,111 @@ spec: spec: description: UprobeProgramSpec defines the desired state of UprobeProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the uprobe. + If Containers is not specified, the uprobe will be attached in the + bpfman-agent container. The ContainerSelector is very flexible and even + allows the selection of all containers in a cluster. If an attempt is + made to attach uprobes to too many containers, it can have a negative + impact on on the cluster. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + func_name: + description: Function to attach the uprobe to. + type: string + offset: + default: 0 + description: Offset added to the address of the function for + uprobe. + format: int64 + type: integer + pid: + description: |- + Only execute uprobe for given process identification number (PID). If PID + is not provided, uprobe executes for all PIDs. + format: int32 + type: integer + retprobe: + default: false + description: Whether the program is a uretprobe. Default is + false + type: boolean + target: + description: Library name or the absolute path to a binary or + library. + type: string + required: + - target + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -119,80 +224,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the uprobe. - If Containers is not specified, the uprobe will be attached in the - bpfman-agent container. The ContainerSelector is very flexible and even - allows the selection of all containers in a cluster. If an attempt is - made to attach uprobes to too many containers, it can have a negative - impact on on the cluster. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - func_name: - description: Function to attach the uprobe to. - type: string globaldata: additionalProperties: format: byte @@ -302,37 +333,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - offset: - default: 0 - description: Offset added to the address of the function for uprobe. - format: int64 - type: integer - pid: + oldmapownerselector: description: |- - Only execute uprobe for given process identification number (PID). If PID - is not provided, uprobe executes for all PIDs. - format: int32 - type: integer - retprobe: - default: false - description: Whether the program is a uretprobe. Default is false - type: boolean - target: - description: Library name or the absolute path to a binary or library. - type: string + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - nodeselector - - target type: object status: - description: UprobeProgramStatus defines the observed state of UprobeProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_xdpnsprograms.yaml b/config/crd/bases/bpfman.io_xdpnsprograms.yaml index 971eb5949..5b63d021a 100644 --- a/config/crd/bases/bpfman.io_xdpnsprograms.yaml +++ b/config/crd/bases/bpfman.io_xdpnsprograms.yaml @@ -61,6 +61,126 @@ spec: spec: description: XdpNsProgramSpec defines the desired state of XdpNsProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + interfaceselector: + description: Selector to determine the network interface (or + interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary interface + on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the bpf program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pass + - dispatcher_return + description: |- + ProceedOn allows the user to call other xdp programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + required: + - containers + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -111,69 +231,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the eBPF - program. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object globaldata: additionalProperties: format: byte @@ -184,23 +241,6 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object - interfaceselector: - description: Selector to determine the network interface (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface on the - node. Only 'true' accepted. - type: boolean - type: object mapownerselector: description: |- MapOwnerSelector is used to select the loaded eBPF program this eBPF program @@ -300,48 +340,73 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: + oldmapownerselector: description: |- - Priority specifies the priority of the bpf program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pass - - dispatcher_return - description: |- - ProceedOn allows the user to call other xdp programs in chain on this exit code. - Multiple values are supported by repeating the parameter. - items: - enum: - - aborted - - drop - - pass - - tx - - redirect - - dispatcher_return - type: string - maxItems: 6 - type: array + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - containers - - interfaceselector - nodeselector - - priority type: object status: description: XdpProgramStatus defines the observed state of XdpProgram properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/bases/bpfman.io_xdpprograms.yaml b/config/crd/bases/bpfman.io_xdpprograms.yaml index 38b1cafb6..0ff37349c 100644 --- a/config/crd/bases/bpfman.io_xdpprograms.yaml +++ b/config/crd/bases/bpfman.io_xdpprograms.yaml @@ -32,6 +32,10 @@ spec: name: InterfaceSelector priority: 1 type: string + - jsonPath: .spec.position + name: Position + priority: 1 + type: string - jsonPath: .spec.proceedon name: ProceedOn priority: 1 @@ -61,6 +65,130 @@ spec: spec: description: XdpProgramSpec defines the desired state of XdpProgram properties: + attach_points: + description: |- + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: + description: |- + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - pods + type: object + interfaceselector: + description: Selector to determine the network interface (or + interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary interface + on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the bpf program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + default: + - pass + - dispatcher_return + description: |- + ProceedOn allows the user to call other xdp programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + required: + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- BpfFunctionName is the name of the function that is the entry point for the BPF @@ -111,74 +239,6 @@ spec: description: Path is used to specify a bytecode object via filepath. type: string type: object - containers: - description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - x-kubernetes-list-type: atomic - required: - - key - - operator - type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object globaldata: additionalProperties: format: byte @@ -189,23 +249,6 @@ spec: is responsible for formatting the byte string appropriately considering such things as size, endianness, alignment and packing of data structures. type: object - interfaceselector: - description: Selector to determine the network interface (or interfaces) - maxProperties: 1 - minProperties: 1 - properties: - interfaces: - description: |- - Interfaces refers to a list of network interfaces to attach the BPF - program to. - items: - type: string - type: array - primarynodeinterface: - description: Attach BPF program to the primary interface on the - node. Only 'true' accepted. - type: boolean - type: object mapownerselector: description: |- MapOwnerSelector is used to select the loaded eBPF program this eBPF program @@ -305,44 +348,74 @@ spec: type: object type: object x-kubernetes-map-type: atomic - priority: + oldmapownerselector: description: |- - Priority specifies the priority of the bpf program in relation to - other programs of the same type with the same attach point. It is a value - from 0 to 1000 where lower values have higher precedence. - format: int32 - maximum: 1000 - minimum: 0 - type: integer - proceedon: - default: - - pass - - dispatcher_return - items: - enum: - - aborted - - drop - - pass - - tx - - redirect - - dispatcher_return - type: string - maxItems: 6 - type: array + ANF-TODO: MapOwnerSelector has been moved to BpfAppCommon. Do not use in + new load/attach split code. + + + OldMapOwnerSelector is used to select the loaded eBPF program this eBPF + program will share a map with. The value is a label applied to the + BpfProgram to select. The selector must resolve to exactly one instance + of a BpfProgram on a given node or the eBPF program will not load. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic required: - bpffunctionname - bytecode - - interfaceselector - nodeselector - - priority type: object status: - description: XdpProgramStatus defines the observed state of XdpProgram + description: BpfAppStatus reflects the status of a BpfApplication or BpfApplicationState + object properties: conditions: description: |- - Conditions houses the global cluster state for the eBPFProgram. The explicit - condition types are defined internally. + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationState object, Conditions contains the + state of the BpfApplication object on the given node. items: description: "Condition contains details for one aspect of the current state of this API Resource.\n---\nThis struct is intended for diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 2b77f35da..5d24eac35 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -18,6 +18,7 @@ resources: - bases/bpfman.io_xdpnsprograms.yaml - bases/bpfman.io_uprobensprograms.yaml - bases/bpfman.io_bpfnsapplications.yaml + - bases/bpfman.io_bpfapplicationstates.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: diff --git a/config/openshift/patch.yaml b/config/openshift/patch.yaml index cda171a2d..ab2ed243d 100644 --- a/config/openshift/patch.yaml +++ b/config/openshift/patch.yaml @@ -20,4 +20,4 @@ metadata: data: ## Can be configured at runtime bpfman.log.level: info - bpfman.agent.log.level: info + bpfman.agent.log.level: debug diff --git a/config/rbac/bpfman-agent/role.yaml b/config/rbac/bpfman-agent/role.yaml index a54843bc4..6874d3812 100644 --- a/config/rbac/bpfman-agent/role.yaml +++ b/config/rbac/bpfman-agent/role.yaml @@ -18,6 +18,32 @@ rules: - bpfapplications/finalizers verbs: - update +- apiGroups: + - bpfman.io + resources: + - bpfapplicationstates + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - bpfman.io + resources: + - bpfapplicationstates/finalizers + verbs: + - update +- apiGroups: + - bpfman.io + resources: + - bpfapplicationstates/status + verbs: + - get + - patch + - update - apiGroups: - bpfman.io resources: diff --git a/config/rbac/bpfman-operator/role.yaml b/config/rbac/bpfman-operator/role.yaml index 91bc8b962..68fb2a332 100644 --- a/config/rbac/bpfman-operator/role.yaml +++ b/config/rbac/bpfman-operator/role.yaml @@ -42,6 +42,14 @@ rules: - get - patch - update +- apiGroups: + - bpfman.io + resources: + - bpfapplicationstates + verbs: + - get + - list + - watch - apiGroups: - bpfman.io resources: diff --git a/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml b/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml index b7e8f1bb1..713a9cf4c 100644 --- a/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml +++ b/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml @@ -9,50 +9,88 @@ spec: nodeselector: {} bytecode: image: - url: quay.io/bpfman-bytecode/go-app-counter:latest + url: quay.io/bpfman-bytecode/app-test:latest programs: - - type: Kprobe - kprobe: - bpffunctionname: kprobe_counter - func_name: try_to_wake_up - offset: 0 - retprobe: false - - type: Tracepoint - tracepoint: - bpffunctionname: tracepoint_kill_recorder - names: - - syscalls/sys_enter_kill - - type: TC - tc: - bpffunctionname: stats - interfaceselector: - primarynodeinterface: true - priority: 55 - direction: ingress - - type: TCX + # - type: Kprobe + # kprobe: + # bpffunctionname: kprobe_counter + # attach_points: + # - func_name: try_to_wake_up + # offset: 0 + # retprobe: false + # - type: Tracepoint + # tracepoint: + # bpffunctionname: tracepoint_kill_recorder + # attach_points: + # - name: syscalls/sys_enter_kill + # - type: TC + # tc: + # bpffunctionname: stats + # attach_points: + # - interfaceselector: + # primarynodeinterface: true + # priority: 55 + # direction: ingress + - bpffunctionname: tcx_next + type: TCX tcx: - bpffunctionname: tcx_stats - interfaceselector: - primarynodeinterface: true - priority: 500 - direction: ingress - - type: Uprobe - uprobe: - bpffunctionname: uprobe_counter - func_name: malloc - target: libc - retprobe: false - containers: - namespace: bpfman - pods: - matchLabels: - name: bpfman-daemon - containernames: - - bpfman - - bpfman-agent - - type: XDP + bpffunctionname: tcx_next + attach_points: + - interfaceselector: + primarynodeinterface: true + priority: 500 + direction: ingress + - interfaceselector: + interfaces: + - eth0 + priority: 100 + direction: egress + containers: + namespace: bpfman + pods: + matchLabels: + name: bpfman-daemon + containernames: + - bpfman + - bpfman-agent + # - type: Uprobe + # uprobe: + # bpffunctionname: uprobe_counter + # attach_points: + # - func_name: malloc + # target: libc + # retprobe: false + # containers: + # namespace: bpfman + # pods: + # matchLabels: + # name: bpfman-daemon + # containernames: + # - bpfman + # - bpfman-agent + - bpffunctionname: xdp_pass + type: XDP xdp: - bpffunctionname: xdp_stats - interfaceselector: - primarynodeinterface: true - priority: 55 + bpffunctionname: xdp_pass + attach_points: + - interfaceselector: + primarynodeinterface: true + priority: 55 + - interfaceselector: + interfaces: + - eth0 + priority: 100 + containers: + namespace: bpfman + pods: + matchLabels: + name: bpfman-daemon + containernames: + - bpfman + - bpfman-agent + - bpffunctionname: fentry_test + type: Fentry + fentry: + bpffunctionname: fentry_test + function_name: do_unlinkat + attach: true \ No newline at end of file diff --git a/controllers/app-agent/cl-application-program.go b/controllers/app-agent/cl-application-program.go new file mode 100644 index 000000000..a45a451b6 --- /dev/null +++ b/controllers/app-agent/cl-application-program.go @@ -0,0 +1,553 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package appagent + +import ( + "context" + "fmt" + "reflect" + "time" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + "github.com/bpfman/bpfman-operator/internal" + "github.com/google/uuid" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +//+kubebuilder:rbac:groups=bpfman.io,resources=bpfapplications,verbs=get;list;watch +//+kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationstates,verbs=get;list;watch +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationstates,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationstates/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationstates/finalizers,verbs=update +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplications/finalizers,verbs=update +// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch +// +kubebuilder:rbac:groups=core,resources=nodes,verbs=get;list;watch +// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get + +type BpfApplicationReconciler struct { + ReconcilerCommon + currentApp *bpfmaniov1alpha1.BpfApplication + currentAppState *bpfmaniov1alpha1.BpfApplicationState +} + +// func (r *BpfApplicationReconciler) getRecType() string { +// return internal.ApplicationString +// } + +func (r *BpfApplicationReconciler) getAppStateName() string { + return r.currentAppState.Name +} + +func (r *BpfApplicationReconciler) getNode() *v1.Node { + return r.ourNode +} + +func (r *BpfApplicationReconciler) getNodeSelector() *metav1.LabelSelector { + return &r.currentApp.Spec.NodeSelector +} + +func (r *BpfApplicationReconciler) GetStatus() *bpfmaniov1alpha1.BpfAppStatus { + return &r.currentAppState.Status +} + +func (r *BpfApplicationReconciler) isBeingDeleted() bool { + return !r.currentApp.GetDeletionTimestamp().IsZero() +} + +func (r *BpfApplicationReconciler) updateBpfAppStatus(ctx context.Context, condition metav1.Condition) error { + r.currentAppState.Status.Conditions = nil + meta.SetStatusCondition(&r.currentAppState.Status.Conditions, condition) + return r.Status().Update(ctx, r.currentAppState) +} + +func (r *BpfApplicationReconciler) updateLoadStatus(newCondition bpfmaniov1alpha1.BpfProgramConditionType) { + r.currentAppState.Spec.AppLoadStatus = newCondition +} + +// SetupWithManager sets up the controller with the Manager. +// The Bpfman-Agent should reconcile whenever a BpfApplication object is updated, +// load the programs to the node via bpfman, and then create a bpfProgram object +// to reflect per node state information. +func (r *BpfApplicationReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&bpfmaniov1alpha1.BpfApplication{}, builder.WithPredicates(predicate.And(predicate.GenerationChangedPredicate{}, predicate.ResourceVersionChangedPredicate{}))). + WithOptions(controller.Options{MaxConcurrentReconciles: 1}). + Owns(&bpfmaniov1alpha1.BpfApplicationState{}, + builder.WithPredicates(internal.BpfNodePredicate(r.NodeName)), + ). + // Only trigger reconciliation if node labels change since that could + // make the BpfApplication no longer select the Node. Additionally only + // care about node events specific to our node + Watches( + &v1.Node{}, + &handler.EnqueueRequestForObject{}, + builder.WithPredicates(predicate.And(predicate.LabelChangedPredicate{}, nodePredicate(r.NodeName))), + ). + // Watch for changes in Pod resources in case we are using a container selector. + Watches( + &v1.Pod{}, + &handler.EnqueueRequestForObject{}, + builder.WithPredicates(podOnNodePredicate(r.NodeName)), + ). + Complete(r) +} + +func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + // Initialize node and current program + // r.currentApp = &bpfmaniov1alpha1.BpfApplication{} + r.ourNode = &v1.Node{} + r.Logger = ctrl.Log.WithName("cluster-app") + r.finalizer = internal.BpfApplicationControllerFinalizer + r.recType = internal.ApplicationString + + r.Logger.Info("Enter BpfApplication Reconcile", "Name", req.Name) + + // Lookup K8s node object for this bpfman-agent This should always succeed + if err := r.Get(ctx, types.NamespacedName{Namespace: v1.NamespaceAll, Name: r.NodeName}, r.ourNode); err != nil { + return ctrl.Result{Requeue: false}, fmt.Errorf("failed getting bpfman-agent node %s : %v", + req.NamespacedName, err) + } + + // Get the list of existing BpfApplication objects + appPrograms := &bpfmaniov1alpha1.BpfApplicationList{} + opts := []client.ListOption{} + if err := r.List(ctx, appPrograms, opts...); err != nil { + return ctrl.Result{Requeue: false}, fmt.Errorf("failed getting BpfApplicationPrograms for full reconcile %s : %v", + req.NamespacedName, err) + } + if len(appPrograms.Items) == 0 { + r.Logger.Info("BpfApplicationController found no application Programs") + return ctrl.Result{Requeue: false}, nil + } + + for i, a := range appPrograms.Items { + // ANF-TODO: After load/attach split, we will need to load the code defined + // in the BpfApplication here one time before we go through the list of + // programs. However, for now, we need to keep the current behavior and + // load it for every attachment. + + // Get the corresponding BpfApplicationState object, and if it doesn't + // exist, instantiate a copy, but don't create it until after we've + // processed each program and its attachments. + // Only list bpfPrograms for this *Program and the controller's node + + r.currentApp = &a + + // if bpfAppStateNew is true, then we need to create a new + // BpfApplicationState at the end of the reconcile instead of just + // updating the existing one. + appState, bpfAppStateNew, err := r.getBpfAppState(ctx, true) + if err != nil { + r.Logger.Error(err, "failed to get BpfApplicationState") + return ctrl.Result{}, err + } + r.currentAppState = appState + + // Save a copy of the original BpfApplicationState to check for changes + // at the end of the reconcile process. This approach simplifies the + // code and reduces the risk of errors by avoiding the need to track + // changes throughout. We don't need to do this for new + // BpfApplicationStates because they don't exist yet and will need to be + // created anyway. + var bpfAppStateOriginal *bpfmaniov1alpha1.BpfApplicationState + if !bpfAppStateNew { + bpfAppStateOriginal = r.currentAppState.DeepCopy() + } + + r.Logger.Info("From getBpfAppState", "new", bpfAppStateNew) + + // Make sure the BpfApplication code is loaded on the node. + r.Logger.Info("Calling reconcileLoad()") + err = r.reconcileLoad(r) + if err != nil { + // There's no point continuing to reconcile the attachments if we + // can't load the code. + r.Logger.Error(err, "failed to reconcileLoad") + objectChanged, _ := r.updateBpfAppStateSpec(ctx, bpfAppStateOriginal, bpfAppStateNew) + statusChanged := r.updateStatus(ctx, r, bpfmaniov1alpha1.ProgramReconcileError) + if statusChanged || objectChanged { + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationAgent}, nil + } else { + // If nothing changed, continue with the next BpfApplication. + // Otherwise, one bad BpfApplication can block the rest. + continue + } + } + + // Initialize the BpfApplicationState status to Success. It will be set + // to Error if any of the programs have an error. + bpfApplicationStatus := bpfmaniov1alpha1.ProgramReconcileSuccess + + // function + + // Reconcile each program in the BpfApplication + for _, prog := range a.Spec.Programs { + progState, err := r.getProgState(&prog, r.currentAppState.Spec.Programs) + if err != nil { + // ANF-TODO: This entry should have been created when the + // BpfApplication was loaded. If it's not here, then we need to + // do another load, and we'll need to work out how to do that. + // If we just do a load here for the new program, then it won't + // share global data with the existing programs. So, we need to + // decide whether to just do an incremental load, or unload the + // existing programs and reload everything. In the future, we + // may be able to add more seamless support for incremental + // loads. However, in this POC code, we're going to log an error + // and continue. + r.Logger.Error(fmt.Errorf("ProgramState not found"), + "ProgramState not found", "App Name", r.currentApp.Name, "BpfFunctionName", prog.BpfFunctionName) + continue + } + + switch prog.Type { + // ANF-TODO: Implement support for other program types. + + case bpfmaniov1alpha1.ProgTypeFentry: + rec := &FentryProgramReconciler{ + ReconcilerCommon: r.ReconcilerCommon, + ProgramReconcilerCommon: ProgramReconcilerCommon{ + appCommon: r.currentApp.Spec.BpfAppCommon, + currentProgram: &prog, + currentProgramState: progState, + }, + } + err = rec.reconcileProgram(ctx, rec, r.isBeingDeleted()) + + // case bpfmaniov1alpha1.ProgTypeFexit: + // case bpfmaniov1alpha1.ProgTypeKprobe: + // case bpfmaniov1alpha1.ProgTypeUprobe: + // case bpfmaniov1alpha1.ProgTypeTracepoint: + // case bpfmaniov1alpha1.ProgTypeTC: + + case bpfmaniov1alpha1.ProgTypeTCX: + rec := &TcxProgramReconciler{ + ReconcilerCommon: r.ReconcilerCommon, + ProgramReconcilerCommon: ProgramReconcilerCommon{ + appCommon: r.currentApp.Spec.BpfAppCommon, + currentProgram: &prog, + currentProgramState: progState, + }, + } + err = rec.reconcileProgram(ctx, rec, r.isBeingDeleted()) + + case bpfmaniov1alpha1.ProgTypeXDP: + rec := &XdpProgramReconciler{ + ReconcilerCommon: r.ReconcilerCommon, + ProgramReconcilerCommon: ProgramReconcilerCommon{ + appCommon: r.currentApp.Spec.BpfAppCommon, + currentProgram: &prog, + currentProgramState: progState, + }, + } + err = rec.reconcileProgram(ctx, rec, r.isBeingDeleted()) + + default: + bpfApplicationStatus = bpfmaniov1alpha1.ProgramReconcileError + r.Logger.Error(fmt.Errorf("unsupported bpf program type"), "unsupported bpf program type", "ProgType", prog.Type) + // Skip this program and continue to the next one + continue + } + + if err != nil { + progState.ProgramAttachStatus = bpfmaniov1alpha1.BpfProgCondAttachError + bpfApplicationStatus = bpfmaniov1alpha1.ProgramReconcileError + r.Logger.Error(err, "reconcile failure", "App Name", r.currentApp.Name, "BpfFunctionName", prog.BpfFunctionName, "Type", prog.Type) + } else { + progState.ProgramAttachStatus = bpfmaniov1alpha1.BpfProgCondAttached + r.Logger.Info("reconcile success", "App Name", r.currentApp.Name, "BpfFunctionName", prog.BpfFunctionName, "Type", prog.Type) + } + + r.Logger.Info("Done reconciling program", "Application", i, "Name", r.currentAppState.GetName()) + } + + // We've completed reconciling all programs and if something has + // changed, we need to create or update the BpfApplicationState. + specChanged, err := r.updateBpfAppStateSpec(ctx, bpfAppStateOriginal, bpfAppStateNew) + if err != nil { + r.Logger.Error(err, "failed to update BpfApplicationState", "Name", r.currentAppState.Name) + r.updateStatus(ctx, r, bpfmaniov1alpha1.ProgramReconcileError) + // If there was an error updating the object, request a requeue + // because we can't be sure what was updated and whether the manager + // will requeue us without the request. + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationAgent}, nil + } + + statusChanged := r.updateStatus(ctx, r, bpfApplicationStatus) + + if specChanged || statusChanged { + r.Logger.Info("BpfApplicationState updated", "Name", r.currentAppState.Name, "Spec Changed", + specChanged, "Status Changed", statusChanged) + return ctrl.Result{}, nil + } + + if r.isBeingDeleted() { + r.Logger.Info("BpfApplication is being deleted", "Name", r.currentApp.Name) + if r.removeFinalizer(ctx, r.currentAppState, r.finalizer) { + return ctrl.Result{}, nil + } + } + + // Nothing changed, so continue with next BpfApplication object. + r.Logger.Info("No changes to BpfApplicationState object", "Name", r.currentAppState.Name) + } + + // We're done with all the BpfApplication objects, so we can return. + r.Logger.Info("All BpfApplication objects have been reconciled") + return ctrl.Result{}, nil +} + +// getProgState returns the BpfApplicationProgramState object for the current node. +func (r *BpfApplicationReconciler) getProgState(prog *bpfmaniov1alpha1.BpfApplicationProgram, + programs []bpfmaniov1alpha1.BpfApplicationProgramState) (*bpfmaniov1alpha1.BpfApplicationProgramState, error) { + // ANF-TODO: Finish implementing for other program types. + for _, progState := range programs { + if progState.Type == prog.Type && progState.BpfFunctionName == prog.BpfFunctionName { + switch prog.Type { + case bpfmaniov1alpha1.ProgTypeFentry: + if progState.Fentry.FunctionName == prog.Fentry.FunctionName { + return &progState, nil + } + // case bpfmaniov1alpha1.ProgTypeFexit: + // if progState.Fexit.FunctionName == prog.Fexit.FunctionName { + // return &progState, nil + // } + default: + return &progState, nil + } + } + } + return nil, fmt.Errorf("BpfApplicationProgramState not found") +} + +// updateBpfAppStateSpec creates or updates the BpfApplicationState object if it is +// new or has changed. It returns true if the object was created or updated, and +// an error if the API call fails. If true is returned without an error, the +// reconciler should return immediately because a new reconcile will be +// triggered. If an error is returned, the code should return and request a +// requeue because it's uncertain whether a reconcile will be triggered. If +// false is returned without an error, the reconciler may continue reconciling +// because nothing was changed. +func (r *BpfApplicationReconciler) updateBpfAppStateSpec(ctx context.Context, originalAppState *bpfmaniov1alpha1.BpfApplicationState, + bpfAppStateNew bool) (bool, error) { + + // We've completed reconciling this program and something has + // changed. We need to create or update the BpfApplicationState. + if bpfAppStateNew { + // Create a new BpfApplicationState + r.currentAppState.Spec.UpdateCount = 1 + r.Logger.Info("Creating new BpfApplicationState object", "Name", r.currentAppState.Name, + "bpfAppStateNew", bpfAppStateNew, "UpdateCount", r.currentAppState.Spec.UpdateCount) + if err := r.Create(ctx, r.currentAppState); err != nil { + r.Logger.Error(err, "failed to create BpfApplicationState") + return true, err + } + return r.waitForBpfAppStateUpdate(ctx) + } else if !reflect.DeepEqual(originalAppState.Spec, r.currentAppState.Spec) { + // Update the BpfApplicationState + r.currentAppState.Spec.UpdateCount = r.currentAppState.Spec.UpdateCount + 1 + r.Logger.Info("Updating BpfApplicationState object", "Name", r.currentAppState.Name, "bpfAppStateNew", bpfAppStateNew, "UpdateCount", r.currentAppState.Spec.UpdateCount) + if err := r.Update(ctx, r.currentAppState); err != nil { + r.Logger.Error(err, "failed to update BpfApplicationState") + return true, err + } + return r.waitForBpfAppStateUpdate(ctx) + } + return false, nil +} + +// waitForBpfAppStateUpdate waits for the new BpfApplicationState object to be ready. +// bpfman saves state in the BpfApplicationState object that controls what needs +// to be done, so it is critical for each reconcile attempt to have the updated +// information. However, it takes time for objects to be created or updated, and +// for the API server to be able to return the update. I've seen cases where +// the new object isn't ready when a reconcile is launched too soon after an +// update. A field called "UpdateCount" is used to ensure we get the updated +// object. Kubernetes maintains a similar value called "Generation" which we +// might be able to use instead, but I'm not 100% sure I can trust it yet. When +// waitForBpfAppStateUpdate gets the updated object, it also updates r.currentAppState +// so the object can be used for subsequent operations (like a status update). +// From observations so far on kind, the updated object is sometimes ready on +// the first try, and sometimes it takes one more try. I've not seen it take +// more than one retry. waitForBpfAppStateUpdate currently waits for up to 10 seconds +// (100 * 100ms). +func (r *BpfApplicationReconciler) waitForBpfAppStateUpdate(ctx context.Context) (bool, error) { + const maxRetries = 100 + const retryInterval = 100 * time.Millisecond + + var bpfAppState *bpfmaniov1alpha1.BpfApplicationState + var err error + r.Logger.Info("waitForBpfAppState()", "UpdateCount", r.currentAppState.Spec.UpdateCount, "currentGeneration", r.currentAppState.GetGeneration()) + + for i := 0; i < maxRetries; i++ { + bpfAppState, _, err = r.getBpfAppState(ctx, false) + if err != nil { + // If we get an error, we'll just log it and keep trying. + r.Logger.Info("Error getting BpfApplicationState", "Attempt", i, "error", err) + } else if bpfAppState != nil && bpfAppState.Spec.UpdateCount >= r.currentAppState.Spec.UpdateCount { + r.Logger.Info("Found new bpfAppState", "Attempt", i, "UpdateCount", bpfAppState.Spec.UpdateCount, "currentGeneration", bpfAppState.GetGeneration()) + r.currentAppState = bpfAppState + return true, nil + } + time.Sleep(retryInterval) + } + + r.Logger.Info("Didn't find new BpfApplicationState", "Attempts", maxRetries) + return false, fmt.Errorf("failed to get new BpfApplicationState after %d retries", maxRetries) +} + +// getBpfAppState returns the BpfApplicationState object for the current node. If +// needed to be created, the returned bool will be true. Otherwise, it will be false. +func (r *BpfApplicationReconciler) getBpfAppState(ctx context.Context, createIfNotFound bool) (*bpfmaniov1alpha1.BpfApplicationState, bool, error) { + + appProgramList := &bpfmaniov1alpha1.BpfApplicationStateList{} + + opts := []client.ListOption{ + client.MatchingLabels{ + internal.BpfAppStateOwner: r.currentApp.GetName(), + internal.K8sHostLabel: r.NodeName, + }, + } + + err := r.List(ctx, appProgramList, opts...) + if err != nil { + return nil, false, err + } + + if len(appProgramList.Items) == 1 { + // We got exatly one BpfApplicationState, so return it + return &appProgramList.Items[0], false, nil + } + if len(appProgramList.Items) > 1 { + // This should never happen, but if it does, return an error + return nil, false, fmt.Errorf("more than one BpfProgram found (%d)", len(appProgramList.Items)) + } + // There are no BpfApplicationStates for this BpfApplication on this node. + if createIfNotFound { + return r.createBpfAppState() + } else { + return nil, false, nil + } +} + +func (r *BpfApplicationReconciler) createBpfAppState() (*bpfmaniov1alpha1.BpfApplicationState, bool, error) { + bpfAppState := &bpfmaniov1alpha1.BpfApplicationState{ + ObjectMeta: metav1.ObjectMeta{ + Name: generateUniqueName(r.currentApp.Name), + Finalizers: []string{r.finalizer}, + Labels: map[string]string{ + internal.BpfAppStateOwner: r.currentApp.GetName(), + internal.K8sHostLabel: r.NodeName, + }, + }, + Spec: bpfmaniov1alpha1.BpfApplicationStateSpec{ + Node: r.NodeName, + AppLoadStatus: bpfmaniov1alpha1.BpfProgCondNotLoaded, + UpdateCount: 0, + Programs: []bpfmaniov1alpha1.BpfApplicationProgramState{}, + }, + Status: bpfmaniov1alpha1.BpfAppStatus{Conditions: []metav1.Condition{}}, + } + + err := r.initializeNodeProgramList(bpfAppState) + if err != nil { + return nil, false, fmt.Errorf("failed to initialize BpfApplicationState program list: %v", err) + } + + // Make the corresponding BpfProgramConfig the owner + if err := ctrl.SetControllerReference(r.currentApp, bpfAppState, r.Scheme); err != nil { + return nil, false, fmt.Errorf("failed to set bpfAppState object owner reference: %v", err) + } + + return bpfAppState, true, nil +} + +func (r *BpfApplicationReconciler) initializeNodeProgramList(bpfAppState *bpfmaniov1alpha1.BpfApplicationState) error { + // The list should only be initialized once when the BpfApplication is first + // created. After that, the user can't add or remove programs. + if len(bpfAppState.Spec.Programs) != 0 { + return fmt.Errorf("BpfApplicationState programs list has already been initialized") + } + + for _, prog := range r.currentApp.Spec.Programs { + // Check if it's already on the list. If it is, this is an error + // because a given bpf function can only be loaded once per + // BpfApplication. + _, err := r.getProgState(&prog, bpfAppState.Spec.Programs) + if err == nil { + return fmt.Errorf("duplicate bpf function detected. bpfFunctionName: %s", prog.BpfFunctionName) + } + progState := bpfmaniov1alpha1.BpfApplicationProgramState{ + BpfProgramStateCommon: bpfmaniov1alpha1.BpfProgramStateCommon{ + BpfProgramCommon: prog.BpfProgramCommon, + ProgramAttachStatus: bpfmaniov1alpha1.BpfProgCondNotAttached, + }, + Type: prog.Type, + } + switch prog.Type { + case bpfmaniov1alpha1.ProgTypeFentry: + progState.Fentry = &bpfmaniov1alpha1.FentryProgramInfoState{ + BpfProgramStateCommon: bpfmaniov1alpha1.BpfProgramStateCommon{}, + FentryLoadInfo: prog.Fentry.FentryLoadInfo, + FentryAttachInfoState: bpfmaniov1alpha1.FentryAttachInfoState{ + AttachInfoCommon: bpfmaniov1alpha1.AttachInfoCommon{ + AttachStatus: bpfmaniov1alpha1.BpfProgCondNotAttached, + UUID: uuid.New().String(), + }, + Attach: prog.Fentry.Attach, + }, + } + case bpfmaniov1alpha1.ProgTypeFexit: + panic(fmt.Sprintf("%v not implemented yet", prog.Type)) + case bpfmaniov1alpha1.ProgTypeKprobe: + panic(fmt.Sprintf("%v not implemented yet", prog.Type)) + case bpfmaniov1alpha1.ProgTypeKretprobe: + panic(fmt.Sprintf("%v not implemented yet", prog.Type)) + case bpfmaniov1alpha1.ProgTypeTC: + panic(fmt.Sprintf("%v not implemented yet", prog.Type)) + case bpfmaniov1alpha1.ProgTypeTCX: + progState.TCX = &bpfmaniov1alpha1.TcxProgramInfoState{ + AttachPoints: []bpfmaniov1alpha1.TcxAttachInfoState{}, + } + case bpfmaniov1alpha1.ProgTypeTracepoint: + panic(fmt.Sprintf("%v not implemented yet", prog.Type)) + case bpfmaniov1alpha1.ProgTypeUprobe: + panic(fmt.Sprintf("%v not implemented yet", prog.Type)) + case bpfmaniov1alpha1.ProgTypeUretprobe: + panic(fmt.Sprintf("%v not implemented yet", prog.Type)) + case bpfmaniov1alpha1.ProgTypeXDP: + progState.XDP = &bpfmaniov1alpha1.XdpProgramInfoState{ + AttachPoints: []bpfmaniov1alpha1.XdpAttachInfoState{}, + } + default: + panic(fmt.Sprintf("unexpected EBPFProgType: %#v", prog.Type)) + } + + bpfAppState.Spec.Programs = append(bpfAppState.Spec.Programs, progState) + } + + return nil +} diff --git a/controllers/app-agent/cl-application-program_test.go b/controllers/app-agent/cl-application-program_test.go new file mode 100644 index 000000000..f1aaa89d2 --- /dev/null +++ b/controllers/app-agent/cl-application-program_test.go @@ -0,0 +1,240 @@ +package appagent + +import ( + "context" + "reflect" + "testing" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + agenttestutils "github.com/bpfman/bpfman-operator/controllers/app-agent/internal/test-utils" + "github.com/bpfman/bpfman-operator/internal" + testutils "github.com/bpfman/bpfman-operator/internal/test-utils" + "github.com/stretchr/testify/require" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes/scheme" +) + +func TestBpfApplicationControllerCreate(t *testing.T) { + var ( + // global config + appProgramName = "fakeAppProgram" + namespace = "bpfman" + bytecodePath = "/tmp/hello.o" + xdpBpfFunctionName = "XdpTest" + tcxBpfFunctionName = "TcxTest" + fentryBpfFunctionName = "FentryTest" + fentryAttachFunction = "FentryAttachTest" + priority = 50 + fakeNode = testutils.NewNode("fake-control-plane") + fakeInt0 = "eth0" + // fakeInt1 = "eth1" + ctx = context.TODO() + // appProgramId0 = "" + // attachPoint0 = fakeInt0 + // appProgramId1 = "" + // attachPoint1 = fakeInt1 + // bpfProgEth0 = &bpfmaniov1alpha1.BpfProgram{} + // bpfProgEth1 = &bpfmaniov1alpha1.BpfProgram{} + // fakeUID0 = "ef71d42c-aa21-48e8-a697-82391d801a80" + // fakeUID1 = "ef71d42c-aa21-48e8-a697-82391d801a81" + ) + + programs := []bpfmaniov1alpha1.BpfApplicationProgram{} + + fakeInts := []string{fakeInt0} + + interfaceSelector := bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &fakeInts, + } + + proceedOn := []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), + bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return")} + + xdpAttachInfo := bpfmaniov1alpha1.XdpAttachInfo{ + InterfaceSelector: interfaceSelector, + Containers: nil, + Priority: int32(priority), + ProceedOn: proceedOn, + } + + xdpProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: xdpBpfFunctionName, + }, + Type: bpfmaniov1alpha1.ProgTypeXDP, + XDP: &bpfmaniov1alpha1.XdpProgramInfo{ + AttachPoints: []bpfmaniov1alpha1.XdpAttachInfo{xdpAttachInfo}, + }, + } + + programs = append(programs, xdpProgram) + + tcxAttachInfo := bpfmaniov1alpha1.TcxAttachInfo{ + InterfaceSelector: interfaceSelector, + Containers: nil, + Direction: "ingress", + Priority: int32(priority), + } + tcProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: tcxBpfFunctionName, + }, + Type: bpfmaniov1alpha1.ProgTypeTCX, + TCX: &bpfmaniov1alpha1.TcxProgramInfo{ + AttachPoints: []bpfmaniov1alpha1.TcxAttachInfo{tcxAttachInfo}, + }, + } + programs = append(programs, tcProgram) + + fentryProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: fentryBpfFunctionName, + }, + Type: bpfmaniov1alpha1.ProgTypeFentry, + Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ + FentryLoadInfo: bpfmaniov1alpha1.FentryLoadInfo{ + FunctionName: fentryAttachFunction, + }, + FentryAttachInfo: bpfmaniov1alpha1.FentryAttachInfo{ + Attach: true, + }, + }, + } + programs = append(programs, fentryProgram) + + bpfApp := &bpfmaniov1alpha1.BpfApplication{ + ObjectMeta: metav1.ObjectMeta{ + Name: appProgramName, + }, + Spec: bpfmaniov1alpha1.BpfApplicationSpec{ + BpfAppCommon: bpfmaniov1alpha1.BpfAppCommon{ + NodeSelector: metav1.LabelSelector{}, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + Programs: programs, + }, + } + + // Objects to track in the fake client. + objs := []runtime.Object{fakeNode, bpfApp} + + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, bpfApp) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfApplicationList{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfApplication{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfApplicationStateList{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfApplicationState{}) + + // Create a fake client to mock API calls. + cl := fake.NewClientBuilder().WithStatusSubresource(bpfApp).WithStatusSubresource(&bpfmaniov1alpha1.BpfApplicationState{}).WithRuntimeObjects(objs...).Build() + + cli := agenttestutils.NewBpfmanClientFake() + + rc := ReconcilerCommon{ + Client: cl, + Scheme: s, + BpfmanClient: cli, + NodeName: fakeNode.Name, + ourNode: fakeNode, + } + + // Set development Logger, so we can see all logs in tests. + logf.SetLogger(zap.New(zap.UseFlagOptions(&zap.Options{Development: true}))) + + // Create a ReconcileMemcached object with the scheme and fake client. + r := &BpfApplicationReconciler{ + ReconcilerCommon: rc, + } + + // Mock request to simulate Reconcile() being called on an event for a + // watched resource . + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: appProgramName, + Namespace: namespace, + }, + } + + // First reconcile should create the BpfApplicationState object + r.Logger.Info("First reconcile") + res, err := r.Reconcile(ctx, req) + require.NoError(t, err) + + r.Logger.Info("First reconcile", "res:", res, "err:", err) + + // Require no requeue + require.False(t, res.Requeue) + + // Check the BpfProgram Object was created successfully + bpfAppState, bpfAppStateNew, err := r.getBpfAppState(ctx, false) + require.NoError(t, err) + + // Make sure we got bpfAppState from the api server and didn't create a new + // one. + require.Equal(t, false, bpfAppStateNew) + + require.Equal(t, 1, len(bpfAppState.Status.Conditions)) + require.Equal(t, string(bpfmaniov1alpha1.ProgramReconcileSuccess), bpfAppState.Status.Conditions[0].Type) + + require.Equal(t, fakeNode.Name, bpfAppState.Labels[internal.K8sHostLabel]) + + require.Equal(t, appProgramName, bpfAppState.Labels[internal.BpfAppStateOwner]) + + require.Equal(t, internal.BpfApplicationControllerFinalizer, bpfAppState.Finalizers[0]) + + // Do a 2nd reconcile and make sure it doesn't change + r.Logger.Info("Second reconcile") + res, err = r.Reconcile(ctx, req) + require.NoError(t, err) + + // Require no requeue + require.False(t, res.Requeue) + + r.Logger.Info("Second reconcile", "res:", res, "err:", err) + + // Check the BpfProgram Object was created successfully + bpfAppState2, bpfAppStateNew, err := r.getBpfAppState(ctx, false) + require.NoError(t, err) + + // Make sure we got bpfAppState from the api server and didn't create a new + // one. + require.Equal(t, false, bpfAppStateNew) + + // Check that the bpfAppState was not updated + require.True(t, reflect.DeepEqual(bpfAppState, bpfAppState2)) + + currentXdpProgram := programs[0] + + attachPoint := bpfAppState2.Spec.Programs[0].XDP.AttachPoints[0] + + xdpReconciler := &XdpProgramReconciler{ + ReconcilerCommon: rc, + ProgramReconcilerCommon: ProgramReconcilerCommon{ + appCommon: bpfmaniov1alpha1.BpfAppCommon{ + NodeSelector: metav1.LabelSelector{}, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + currentProgram: ¤tXdpProgram, + currentProgramState: &bpfmaniov1alpha1.BpfApplicationProgramState{}, + }, + currentAttachPoint: &attachPoint, + } + + loadRequest, err := xdpReconciler.getLoadRequest(nil) + require.NoError(t, err) + + require.Equal(t, xdpBpfFunctionName, loadRequest.Name) + require.Equal(t, uint32(6), loadRequest.ProgramType) +} diff --git a/controllers/app-agent/cl-fentry-program.go b/controllers/app-agent/cl-fentry-program.go new file mode 100644 index 000000000..c7ccb1bb8 --- /dev/null +++ b/controllers/app-agent/cl-fentry-program.go @@ -0,0 +1,192 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//lint:file-ignore U1000 Linter claims functions unused, but are required for generic + +package appagent + +import ( + "context" + "fmt" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + bpfmanagentinternal "github.com/bpfman/bpfman-operator/controllers/app-agent/internal" + internal "github.com/bpfman/bpfman-operator/internal" + gobpfman "github.com/bpfman/bpfman/clients/gobpfman/v1" + + v1 "k8s.io/api/core/v1" +) + +//+kubebuilder:rbac:groups=bpfman.io,resources=fentryprograms,verbs=get;list;watch + +// BpfProgramReconciler reconciles a BpfProgram object +type FentryProgramReconciler struct { + ReconcilerCommon + ProgramReconcilerCommon +} + +func (r *FentryProgramReconciler) getProgId() *uint32 { + return r.currentProgramState.ProgramId +} + +func (r *FentryProgramReconciler) getProgType() internal.ProgramType { + return internal.Tracing +} + +func (r *FentryProgramReconciler) getNode() *v1.Node { + return r.ourNode +} + +func (r *FentryProgramReconciler) getBpfGlobalData() map[string][]byte { + return r.appCommon.GlobalData +} + +func (r *FentryProgramReconciler) shouldAttach() bool { + return r.currentProgramState.Fentry.ShouldAttach +} + +func (r *FentryProgramReconciler) getUUID() string { + return r.currentProgramState.Fentry.UUID +} + +func (r *FentryProgramReconciler) getAttachId() *uint32 { + return r.currentProgramState.Fentry.AttachId +} + +func (r *FentryProgramReconciler) setAttachId(id *uint32) { + r.currentProgramState.Fentry.AttachId = id +} + +func (r *FentryProgramReconciler) setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) bool { + return updateSimpleStatus(&r.currentProgramState.Fentry.AttachStatus, status) +} + +func (r *FentryProgramReconciler) getAttachStatus() bpfmaniov1alpha1.BpfProgramConditionType { + return r.currentProgramState.Fentry.AttachStatus +} + +func (r *FentryProgramReconciler) getLoadRequest(mapOwnerId *uint32) (*gobpfman.LoadRequest, error) { + r.Logger.Info("Getting load request", "bpfFunctionName", r.currentProgram.BpfFunctionName, + "mapOwnerId", mapOwnerId, "ByteCode", r.appCommon.ByteCode) + + bytecode, err := bpfmanagentinternal.GetBytecode(r.Client, &r.appCommon.ByteCode) + if err != nil { + return nil, fmt.Errorf("failed to process bytecode selector: %v", err) + } + + // ANF-TODO: This is a temporary workaround for backwards compatibility. + // Fix it after old code removed. + var bpfFunctionName string + if r.currentProgram.BpfFunctionName != "" { + bpfFunctionName = r.currentProgram.BpfFunctionName + } else { + bpfFunctionName = r.currentProgram.Fentry.BpfFunctionName + } + + loadRequest := gobpfman.LoadRequest{ + Bytecode: bytecode, + Name: bpfFunctionName, + ProgramType: uint32(internal.Tracing), + Attach: &gobpfman.AttachInfo{ + Info: &gobpfman.AttachInfo_FentryAttachInfo{ + FentryAttachInfo: &gobpfman.FentryAttachInfo{ + FnName: r.currentProgram.Fentry.FunctionName, + }, + }, + }, + Metadata: map[string]string{internal.UuidMetadataKey: string(r.currentProgramState.Fentry.UUID), + internal.ProgramNameKey: "BpfApplication"}, + GlobalData: r.appCommon.GlobalData, + MapOwnerId: mapOwnerId, + } + + return &loadRequest, nil +} + +// updateAttachInfo processes the *ProgramInfo and updates the list of attach +// points contained in *AttachInfoState. +func (r *FentryProgramReconciler) updateAttachInfo(ctx context.Context, isBeingDeleted bool) error { + r.Logger.Info("Fentry updateAttachInfo()", "isBeingDeleted", isBeingDeleted) + + if isBeingDeleted { + // If the program is being deleted, we don't need to do anything else. + // + // ANF-TODO: When we have load/attach split, we shouldn't even need to + // set ShouldAttach to false above, because unloading the program should + // remove all attachments and updateAttachInfo won't be called. We + // probably should delete AttachPoints when unloading the program. + + r.currentProgramState.Fentry.ShouldAttach = false + return nil + } + + r.currentProgramState.Fentry.ShouldAttach = r.currentProgram.Fentry.Attach + + return nil +} + +// processAttachInfo processes the attach points in *AttachInfoState. Based on +// the current state, it calls bpfman to attach or detach, or does nothing if +// the state is correct. It returns a boolean indicating if any changes were +// made. +// +// ANF-TODO: Generalize this function and move it into common. +func (r *FentryProgramReconciler) processAttachInfo(ctx context.Context, mapOwnerStatus *MapOwnerParamStatus) error { + r.Logger.Info("Processing attach info", "bpfFunctionName", r.currentProgram.Fentry.BpfFunctionName, + "mapOwnerStatus", mapOwnerStatus) + + // Get existing ebpf state from bpfman. + loadedBpfPrograms, err := bpfmanagentinternal.ListBpfmanPrograms(ctx, r.BpfmanClient, r.getProgType()) + if err != nil { + r.Logger.Error(err, "failed to list loaded bpfman programs") + updateSimpleStatus(&r.currentProgramState.ProgramAttachStatus, bpfmaniov1alpha1.BpfProgCondAttachError) + return fmt.Errorf("failed to list loaded bpfman programs: %v", err) + } + + _, err = r.reconcileBpfAttachment(ctx, r, loadedBpfPrograms, mapOwnerStatus) + + return err +} + +// removeAttachPoints removes attach points from a slice of attach points based on the keys in the map. +func (r *FentryProgramReconciler) removeAttachPoints(attachPoints []bpfmaniov1alpha1.FentryAttachInfoState, attachPointsToRemove map[int]bool) []bpfmaniov1alpha1.FentryAttachInfoState { + var remainingAttachPoints []bpfmaniov1alpha1.FentryAttachInfoState + for i, a := range attachPoints { + if _, ok := attachPointsToRemove[i]; !ok { + remainingAttachPoints = append(remainingAttachPoints, a) + } + } + return remainingAttachPoints +} + +// // getInterfaces expands FentryAttachInfo into a list of specific attach points. It works pretty much like the old getExpectedBpfPrograms. +// func (r *FentryProgramReconciler) getExpectedAttachPoints(ctx context.Context, attachInfo bpfmaniov1alpha1.FentryAttachInfo) ([]bpfmaniov1alpha1.FentryAttachInfoState, error) { +// attachPoints := []bpfmaniov1alpha1.FentryAttachInfoState{} + +// if r.currentProgram.Fentry.Attach { +// attachPoint := bpfmaniov1alpha1.FentryAttachInfoState{ +// AttachInfoCommon: bpfmaniov1alpha1.AttachInfoCommon{ +// ShouldAttach: r.currentProgram.Fentry.Attach, +// UUID: uuid.New().String(), +// AttachId: nil, +// AttachStatus: bpfmaniov1alpha1.BpfProgCondNotAttached, +// }, +// } +// attachPoints = append(attachPoints, attachPoint) +// } + +// return attachPoints, nil +// } diff --git a/controllers/app-agent/cl-tcx-program.go b/controllers/app-agent/cl-tcx-program.go new file mode 100644 index 000000000..c27d72416 --- /dev/null +++ b/controllers/app-agent/cl-tcx-program.go @@ -0,0 +1,321 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//lint:file-ignore U1000 Linter claims functions unused, but are required for generic + +package appagent + +import ( + "context" + "fmt" + "reflect" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + bpfmanagentinternal "github.com/bpfman/bpfman-operator/controllers/app-agent/internal" + internal "github.com/bpfman/bpfman-operator/internal" + gobpfman "github.com/bpfman/bpfman/clients/gobpfman/v1" + "github.com/google/uuid" + + v1 "k8s.io/api/core/v1" +) + +//+kubebuilder:rbac:groups=bpfman.io,resources=tcxprograms,verbs=get;list;watch + +// BpfProgramReconciler reconciles a BpfProgram object +type TcxProgramReconciler struct { + ReconcilerCommon + ProgramReconcilerCommon + currentAttachPoint *bpfmaniov1alpha1.TcxAttachInfoState +} + +func (r *TcxProgramReconciler) getProgId() *uint32 { + return r.currentProgramState.ProgramId +} + +func (r *TcxProgramReconciler) getProgType() internal.ProgramType { + return internal.Tc +} + +func (r *TcxProgramReconciler) getNode() *v1.Node { + return r.ourNode +} + +func (r *TcxProgramReconciler) getBpfGlobalData() map[string][]byte { + return r.appCommon.GlobalData +} + +func (r *TcxProgramReconciler) shouldAttach() bool { + return r.currentAttachPoint.ShouldAttach +} + +func (r *TcxProgramReconciler) getUUID() string { + return r.currentAttachPoint.UUID +} + +func (r *TcxProgramReconciler) getAttachId() *uint32 { + return r.currentAttachPoint.AttachId +} + +func (r *TcxProgramReconciler) setAttachId(id *uint32) { + r.currentAttachPoint.AttachId = id +} + +func (r *TcxProgramReconciler) setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) bool { + return updateSimpleStatus(&r.currentAttachPoint.AttachStatus, status) +} + +func (r *TcxProgramReconciler) getAttachStatus() bpfmaniov1alpha1.BpfProgramConditionType { + return r.currentAttachPoint.AttachStatus +} + +func (r *TcxProgramReconciler) getLoadRequest(mapOwnerId *uint32) (*gobpfman.LoadRequest, error) { + + r.Logger.Info("Getting load request", "bpfFunctionName", r.currentProgram.BpfFunctionName, "reqAttachInfo", r.currentAttachPoint, "mapOwnerId", + mapOwnerId, "ByteCode", r.appCommon.ByteCode) + + bytecode, err := bpfmanagentinternal.GetBytecode(r.Client, &r.appCommon.ByteCode) + if err != nil { + return nil, fmt.Errorf("failed to process bytecode selector: %v", err) + } + + attachInfo := &gobpfman.TCXAttachInfo{ + Priority: r.currentAttachPoint.Priority, + Iface: r.currentAttachPoint.IfName, + Direction: r.currentAttachPoint.Direction, + } + + if r.currentAttachPoint.ContainerPid != nil { + netns := fmt.Sprintf("/host/proc/%d/ns/net", *r.currentAttachPoint.ContainerPid) + attachInfo.Netns = &netns + } + + // ANF-TODO: This is a temporary workaround for backwards compatibility. + // Fix it after old code removed. + var bpfFunctionName string + if r.currentProgram.BpfFunctionName != "" { + bpfFunctionName = r.currentProgram.BpfFunctionName + } else { + bpfFunctionName = r.currentProgram.TCX.BpfFunctionName + } + + loadRequest := gobpfman.LoadRequest{ + Bytecode: bytecode, + // ANF-TODO: Name should come from + Name: bpfFunctionName, + ProgramType: uint32(internal.Tc), + Attach: &gobpfman.AttachInfo{ + Info: &gobpfman.AttachInfo_TcxAttachInfo{ + TcxAttachInfo: attachInfo, + }, + }, + Metadata: map[string]string{internal.UuidMetadataKey: string(r.currentAttachPoint.UUID), internal.ProgramNameKey: "BpfApplication"}, + GlobalData: r.appCommon.GlobalData, + MapOwnerId: mapOwnerId, + } + + return &loadRequest, nil +} + +// updateAttachInfo processes the *ProgramInfo and updates the list of attach +// points contained in *AttachInfoState. +func (r *TcxProgramReconciler) updateAttachInfo(ctx context.Context, isBeingDeleted bool) error { + r.Logger.Info("TCX updateAttachInfo()", "isBeingDeleted", isBeingDeleted) + + // Set ShouldAttach for all attach points in the node CRD to false. We'll + // update this in the next step for all attach points that are still + // present. + for i := range r.currentProgramState.TCX.AttachPoints { + r.Logger.Info("Setting ShouldAttach to false", "index", i) + r.currentProgramState.TCX.AttachPoints[i].ShouldAttach = false + } + + if isBeingDeleted { + // If the program is being deleted, we don't need to do anything else. + // + // ANF-TODO: When we have load/attach split, we shouldn't even need to + // set ShouldAttach to false above, because unloading the program should + // remove all attachments and updateAttachInfo won't be called. We + // probably should delete AttachPoints when unloading the program. + return nil + } + + for _, attachInfo := range r.currentProgram.TCX.AttachPoints { + expectedAttachPoints, error := r.getExpectedAttachPoints(ctx, attachInfo) + if error != nil { + return fmt.Errorf("failed to get node attach points: %v", error) + } + for _, attachPoint := range expectedAttachPoints { + index := r.findAttachPoint(attachPoint) + if index != nil { + // Attach point already exists, so set ShouldAttach to true. + r.Logger.Info("Setting ShouldAttach to true", "index", *index) + r.currentProgramState.TCX.AttachPoints[*index].AttachInfoCommon.ShouldAttach = true + } else { + // Attach point doesn't exist, so add it. + r.Logger.Info("Attach point doesn't exist. Adding it.") + r.currentProgramState.TCX.AttachPoints = append(r.currentProgramState.TCX.AttachPoints, attachPoint) + } + } + } + + // If any existing attach point is no longer on a list of expected attach + // points, ShouldAttach will remain set to false and it will get detached in + // a following step. + + return nil +} + +// ANF-TODO: Confirm what constitutes a match between two attach points. E.g., +// what if everything the same, but the priority and/or proceed_on values are +// different? +func (r *TcxProgramReconciler) findAttachPoint(attachInfoState bpfmaniov1alpha1.TcxAttachInfoState) *int { + for i, a := range r.currentProgramState.TCX.AttachPoints { + // attachInfoState is the same as a if the the following fields are the + // same: IfName, ContainerPid, Priority, and Direction. + if a.IfName == attachInfoState.IfName && reflect.DeepEqual(a.ContainerPid, attachInfoState.ContainerPid) && + a.Priority == attachInfoState.Priority && a.Direction == attachInfoState.Direction { + return &i + } + } + return nil +} + +// processAttachInfo processes the attach points in *AttachInfoState. Based on +// the current state, it calls bpfman to attach or detach, or does nothing if +// the state is correct. It returns a boolean indicating if any changes were +// made. +// +// ANF-TODO: Generalize this function and move it into common. +func (r *TcxProgramReconciler) processAttachInfo(ctx context.Context, mapOwnerStatus *MapOwnerParamStatus) error { + r.Logger.Info("Processing attach info", "bpfFunctionName", r.currentProgram.TCX.BpfFunctionName, + "mapOwnerStatus", mapOwnerStatus) + + // Get existing ebpf state from bpfman. + loadedBpfPrograms, err := bpfmanagentinternal.ListBpfmanPrograms(ctx, r.BpfmanClient, internal.Tc) + if err != nil { + r.Logger.Error(err, "failed to list loaded bpfman programs") + updateSimpleStatus(&r.currentProgramState.ProgramAttachStatus, bpfmaniov1alpha1.BpfProgCondAttachError) + return fmt.Errorf("failed to list loaded bpfman programs: %v", err) + } + + // The following map is used to keep track of attach points that need to be + // removed. If it's not empty at the end of the loop, we'll remove the + // attach points. + attachPointsToRemove := make(map[int]bool) + + var lastReconcileAttachmentError error = nil + for i := range r.currentProgramState.TCX.AttachPoints { + r.currentAttachPoint = &r.currentProgramState.TCX.AttachPoints[i] + remove, err := r.reconcileBpfAttachment(ctx, r, loadedBpfPrograms, mapOwnerStatus) + if err != nil { + r.Logger.Error(err, "failed to reconcile bpf attachment", "index", i) + // All errors are logged, but the last error is saved to return and + // we continue to process the rest of the attach points so errors + // don't block valid attach points. + lastReconcileAttachmentError = err + } + + if remove { + r.Logger.Info("Marking attach point for removal", "index", i) + attachPointsToRemove[i] = true + } + } + + if len(attachPointsToRemove) > 0 { + r.Logger.Info("Removing attach points", "attachPointsToRemove", attachPointsToRemove) + r.currentProgramState.TCX.AttachPoints = r.removeAttachPoints(r.currentProgramState.TCX.AttachPoints, attachPointsToRemove) + } + + return lastReconcileAttachmentError +} + +// removeAttachPoints removes attach points from a slice of attach points based on the keys in the map. +func (r *TcxProgramReconciler) removeAttachPoints(attachPoints []bpfmaniov1alpha1.TcxAttachInfoState, attachPointsToRemove map[int]bool) []bpfmaniov1alpha1.TcxAttachInfoState { + var remainingAttachPoints []bpfmaniov1alpha1.TcxAttachInfoState + for i, a := range attachPoints { + if _, ok := attachPointsToRemove[i]; !ok { + remainingAttachPoints = append(remainingAttachPoints, a) + } + } + return remainingAttachPoints +} + +// getInterfaces expands TcxAttachInfo into a list of specific attach points. It works pretty much like the old getExpectedBpfPrograms. +func (r *TcxProgramReconciler) getExpectedAttachPoints(ctx context.Context, attachInfo bpfmaniov1alpha1.TcxAttachInfo, +) ([]bpfmaniov1alpha1.TcxAttachInfoState, error) { + interfaces, err := getInterfaces(&attachInfo.InterfaceSelector, r.ourNode) + if err != nil { + return nil, fmt.Errorf("failed to get interfaces for TcxProgram: %v", err) + } + + nodeAttachPoints := []bpfmaniov1alpha1.TcxAttachInfoState{} + + if attachInfo.Containers != nil { + // There is a container selector, so see if there are any matching + // containers on this node. + containerInfo, err := r.Containers.GetContainers( + ctx, + attachInfo.Containers.Namespace, + attachInfo.Containers.Pods, + attachInfo.Containers.ContainerNames, + r.Logger, + ) + if err != nil { + return nil, fmt.Errorf("failed to get container pids: %v", err) + } + + if containerInfo != nil && len(*containerInfo) != 0 { + // Containers were found, so create attach points. + for i := range *containerInfo { + container := (*containerInfo)[i] + for _, iface := range interfaces { + containerPid := uint32(container.pid) + attachPoint := bpfmaniov1alpha1.TcxAttachInfoState{ + AttachInfoCommon: bpfmaniov1alpha1.AttachInfoCommon{ + ShouldAttach: true, + UUID: uuid.New().String(), + AttachId: nil, + AttachStatus: bpfmaniov1alpha1.BpfProgCondNotAttached, + }, + IfName: iface, + ContainerPid: &containerPid, + Priority: attachInfo.Priority, + Direction: attachInfo.Direction, + } + nodeAttachPoints = append(nodeAttachPoints, attachPoint) + } + } + } + } else { + for _, iface := range interfaces { + attachPoint := bpfmaniov1alpha1.TcxAttachInfoState{ + AttachInfoCommon: bpfmaniov1alpha1.AttachInfoCommon{ + ShouldAttach: true, + UUID: uuid.New().String(), + AttachId: nil, + AttachStatus: bpfmaniov1alpha1.BpfProgCondNotAttached, + }, + IfName: iface, + ContainerPid: nil, + Priority: attachInfo.Priority, + Direction: attachInfo.Direction, + } + nodeAttachPoints = append(nodeAttachPoints, attachPoint) + } + } + + return nodeAttachPoints, nil +} diff --git a/controllers/app-agent/cl-xdp-program.go b/controllers/app-agent/cl-xdp-program.go new file mode 100644 index 000000000..d339d90e1 --- /dev/null +++ b/controllers/app-agent/cl-xdp-program.go @@ -0,0 +1,341 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//lint:file-ignore U1000 Linter claims functions unused, but are required for generic + +package appagent + +import ( + "context" + "fmt" + "reflect" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + bpfmanagentinternal "github.com/bpfman/bpfman-operator/controllers/app-agent/internal" + internal "github.com/bpfman/bpfman-operator/internal" + gobpfman "github.com/bpfman/bpfman/clients/gobpfman/v1" + "github.com/google/uuid" + + v1 "k8s.io/api/core/v1" +) + +//+kubebuilder:rbac:groups=bpfman.io,resources=xdpprograms,verbs=get;list;watch + +// BpfProgramReconciler reconciles a BpfProgram object +type XdpProgramReconciler struct { + ReconcilerCommon + ProgramReconcilerCommon + currentAttachPoint *bpfmaniov1alpha1.XdpAttachInfoState +} + +func (r *XdpProgramReconciler) getProgId() *uint32 { + return r.currentProgramState.ProgramId +} + +func (r *XdpProgramReconciler) getProgType() internal.ProgramType { + return internal.Xdp +} + +func (r *XdpProgramReconciler) getNode() *v1.Node { + return r.ourNode +} + +func (r *XdpProgramReconciler) getBpfGlobalData() map[string][]byte { + return r.appCommon.GlobalData +} + +func (r *XdpProgramReconciler) shouldAttach() bool { + return r.currentAttachPoint.ShouldAttach +} + +func (r *XdpProgramReconciler) getUUID() string { + return r.currentAttachPoint.UUID +} + +func (r *XdpProgramReconciler) getAttachId() *uint32 { + return r.currentAttachPoint.AttachId +} + +func (r *XdpProgramReconciler) setAttachId(id *uint32) { + r.currentAttachPoint.AttachId = id +} + +func (r *XdpProgramReconciler) setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) bool { + return updateSimpleStatus(&r.currentAttachPoint.AttachStatus, status) +} + +func (r *XdpProgramReconciler) getAttachStatus() bpfmaniov1alpha1.BpfProgramConditionType { + return r.currentAttachPoint.AttachStatus +} + +// Must match with bpfman internal types +func xdpProceedOnToInt(proceedOn []bpfmaniov1alpha1.XdpProceedOnValue) []int32 { + var out []int32 + + for _, p := range proceedOn { + switch p { + case "aborted": + out = append(out, 0) + case "drop": + out = append(out, 1) + case "pass": + out = append(out, 2) + case "tx": + out = append(out, 3) + case "redirect": + out = append(out, 4) + case "dispatcher_return": + out = append(out, 31) + } + } + + return out +} + +func (r *XdpProgramReconciler) getLoadRequest(mapOwnerId *uint32) (*gobpfman.LoadRequest, error) { + + r.Logger.Info("Getting load request", "bpfFunctionName", r.currentProgram.BpfFunctionName, "reqAttachInfo", r.currentAttachPoint, "mapOwnerId", + mapOwnerId, "ByteCode", r.appCommon.ByteCode) + + bytecode, err := bpfmanagentinternal.GetBytecode(r.Client, &r.appCommon.ByteCode) + if err != nil { + return nil, fmt.Errorf("failed to process bytecode selector: %v", err) + } + + attachInfo := &gobpfman.XDPAttachInfo{ + Priority: r.currentAttachPoint.Priority, + Iface: r.currentAttachPoint.IfName, + ProceedOn: xdpProceedOnToInt(r.currentAttachPoint.ProceedOn), + } + + if r.currentAttachPoint.ContainerPid != nil { + netns := fmt.Sprintf("/host/proc/%d/ns/net", *r.currentAttachPoint.ContainerPid) + attachInfo.Netns = &netns + } + + // ANF-TODO: This is a temporary workaround for backwards compatibility. + // Fix it after old code removed. + var bpfFunctionName string + if r.currentProgram.BpfFunctionName != "" { + bpfFunctionName = r.currentProgram.BpfFunctionName + } else { + bpfFunctionName = r.currentProgram.XDP.BpfFunctionName + } + + loadRequest := gobpfman.LoadRequest{ + Bytecode: bytecode, + Name: bpfFunctionName, + ProgramType: uint32(internal.Xdp), + Attach: &gobpfman.AttachInfo{ + Info: &gobpfman.AttachInfo_XdpAttachInfo{ + XdpAttachInfo: attachInfo, + }, + }, + Metadata: map[string]string{internal.UuidMetadataKey: string(r.currentAttachPoint.UUID), internal.ProgramNameKey: "BpfApplication"}, + GlobalData: r.appCommon.GlobalData, + MapOwnerId: mapOwnerId, + } + + return &loadRequest, nil +} + +// updateAttachInfo processes the *ProgramInfo and updates the list of attach +// points contained in *AttachInfoState. +func (r *XdpProgramReconciler) updateAttachInfo(ctx context.Context, isBeingDeleted bool) error { + r.Logger.Info("XDP updateAttachInfo()", "isBeingDeleted", isBeingDeleted) + + // Set ShouldAttach for all attach points in the node CRD to false. We'll + // update this in the next step for all attach points that are still + // present. + for i := range r.currentProgramState.XDP.AttachPoints { + r.currentProgramState.XDP.AttachPoints[i].ShouldAttach = false + } + + if isBeingDeleted { + // If the program is being deleted, we don't need to do anything else. + // + // ANF-TODO: When we have load/attach split, we shouldn't even need to + // set ShouldAttach to false above, because unloading the program should + // remove all attachments and updateAttachInfo won't be called. We + // probably should delete AttachPoints when unloading the program. + return nil + } + + for _, attachInfo := range r.currentProgram.XDP.AttachPoints { + expectedAttachPoints, error := r.getExpectedAttachPoints(ctx, attachInfo) + if error != nil { + return fmt.Errorf("failed to get node attach points: %v", error) + } + for _, attachPoint := range expectedAttachPoints { + index := r.findAttachPoint(attachPoint) + if index != nil { + // Attach point already exists, so set ShouldAttach to true. + r.currentProgramState.XDP.AttachPoints[*index].AttachInfoCommon.ShouldAttach = true + } else { + // Attach point doesn't exist, so add it. + r.currentProgramState.XDP.AttachPoints = append(r.currentProgramState.XDP.AttachPoints, attachPoint) + } + } + } + + // If any existing attach point is no longer on a list of expected attach + // points, ShouldAttach will remain set to false and it will get detached in + // a following step. + + return nil +} + +// ANF-TODO: Confirm what constitutes a match between two attach points. E.g., +// what if everything the same, but the priority and/or proceed_on values are +// different? +func (r *XdpProgramReconciler) findAttachPoint(attachInfoState bpfmaniov1alpha1.XdpAttachInfoState) *int { + for i, a := range r.currentProgramState.XDP.AttachPoints { + // attachInfoState is the same as a if the the following fields are the + // same: IfName, ContainerPid, Priority, and ProceedOn. + if a.IfName == attachInfoState.IfName && reflect.DeepEqual(a.ContainerPid, attachInfoState.ContainerPid) && + a.Priority == attachInfoState.Priority && reflect.DeepEqual(a.ProceedOn, attachInfoState.ProceedOn) { + return &i + } + } + return nil +} + +// processAttachInfo processes the attach points in *AttachInfoState. Based on +// the current state, it calls bpfman to attach or detach, or does nothing if +// the state is correct. It returns a boolean indicating if any changes were +// made. +// +// ANF-TODO: Generalize this function and move it into common. +func (r *XdpProgramReconciler) processAttachInfo(ctx context.Context, mapOwnerStatus *MapOwnerParamStatus) error { + r.Logger.Info("Processing attach info", "bpfFunctionName", r.currentProgram.XDP.BpfFunctionName, + "mapOwnerStatus", mapOwnerStatus) + + // Get existing ebpf state from bpfman. + loadedBpfPrograms, err := bpfmanagentinternal.ListBpfmanPrograms(ctx, r.BpfmanClient, internal.Xdp) + if err != nil { + r.Logger.Error(err, "failed to list loaded bpfman programs") + updateSimpleStatus(&r.currentProgramState.ProgramAttachStatus, bpfmaniov1alpha1.BpfProgCondAttachError) + return fmt.Errorf("failed to list loaded bpfman programs: %v", err) + } + + // The following map is used to keep track of attach points that need to be + // removed. If it's not empty at the end of the loop, we'll remove the + // attach points. + attachPointsToRemove := make(map[int]bool) + + var lastReconcileAttachmentError error = nil + for i := range r.currentProgramState.XDP.AttachPoints { + r.currentAttachPoint = &r.currentProgramState.XDP.AttachPoints[i] + remove, err := r.reconcileBpfAttachment(ctx, r, loadedBpfPrograms, mapOwnerStatus) + if err != nil { + r.Logger.Error(err, "failed to reconcile bpf attachment", "index", i) + // All errors are logged, but the last error is saved to return and + // we continue to process the rest of the attach points so errors + // don't block valid attach points. + lastReconcileAttachmentError = err + } + + if remove { + r.Logger.Info("Marking attach point for removal", "index", i) + attachPointsToRemove[i] = true + } + } + + if len(attachPointsToRemove) > 0 { + r.Logger.Info("Removing attach points", "attachPointsToRemove", attachPointsToRemove) + r.currentProgramState.XDP.AttachPoints = r.removeAttachPoints(r.currentProgramState.XDP.AttachPoints, attachPointsToRemove) + } + + return lastReconcileAttachmentError +} + +// removeAttachPoints removes attach points from a slice of attach points based on the keys in the map. +func (r *XdpProgramReconciler) removeAttachPoints(attachPoints []bpfmaniov1alpha1.XdpAttachInfoState, attachPointsToRemove map[int]bool) []bpfmaniov1alpha1.XdpAttachInfoState { + var newAttachPoints []bpfmaniov1alpha1.XdpAttachInfoState + for i, a := range attachPoints { + if _, ok := attachPointsToRemove[i]; !ok { + newAttachPoints = append(newAttachPoints, a) + } + } + return newAttachPoints +} + +// getInterfaces expands XdpAttachInfo into a list of specific attach points. It works pretty much like the old getExpectedBpfPrograms. +func (r *XdpProgramReconciler) getExpectedAttachPoints(ctx context.Context, attachInfo bpfmaniov1alpha1.XdpAttachInfo, +) ([]bpfmaniov1alpha1.XdpAttachInfoState, error) { + interfaces, err := getInterfaces(&attachInfo.InterfaceSelector, r.ourNode) + if err != nil { + return nil, fmt.Errorf("failed to get interfaces for XdpProgram: %v", err) + } + + nodeAttachPoints := []bpfmaniov1alpha1.XdpAttachInfoState{} + + if attachInfo.Containers != nil { + // There is a container selector, so see if there are any matching + // containers on this node. + containerInfo, err := r.Containers.GetContainers( + ctx, + attachInfo.Containers.Namespace, + attachInfo.Containers.Pods, + attachInfo.Containers.ContainerNames, + r.Logger, + ) + if err != nil { + return nil, fmt.Errorf("failed to get container pids: %v", err) + } + + if containerInfo != nil && len(*containerInfo) != 0 { + // Containers were found, so create attach points. + for i := range *containerInfo { + container := (*containerInfo)[i] + for _, iface := range interfaces { + containerPid := uint32(container.pid) + attachPoint := bpfmaniov1alpha1.XdpAttachInfoState{ + AttachInfoCommon: bpfmaniov1alpha1.AttachInfoCommon{ + ShouldAttach: true, + UUID: uuid.New().String(), + AttachId: nil, + AttachStatus: bpfmaniov1alpha1.BpfProgCondNotAttached, + }, + IfName: iface, + ContainerPid: &containerPid, + Priority: attachInfo.Priority, + ProceedOn: attachInfo.ProceedOn, + } + nodeAttachPoints = append(nodeAttachPoints, attachPoint) + } + } + } + } else { + for _, iface := range interfaces { + attachPoint := bpfmaniov1alpha1.XdpAttachInfoState{ + AttachInfoCommon: bpfmaniov1alpha1.AttachInfoCommon{ + ShouldAttach: true, + UUID: uuid.New().String(), + AttachId: nil, + AttachStatus: bpfmaniov1alpha1.BpfProgCondNotAttached, + }, + IfName: iface, + ContainerPid: nil, + Priority: attachInfo.Priority, + ProceedOn: attachInfo.ProceedOn, + } + nodeAttachPoints = append(nodeAttachPoints, attachPoint) + } + } + + return nodeAttachPoints, nil +} diff --git a/controllers/app-agent/common.go b/controllers/app-agent/common.go new file mode 100644 index 000000000..31e8dcaa5 --- /dev/null +++ b/controllers/app-agent/common.go @@ -0,0 +1,548 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package appagent + +import ( + "context" + "fmt" + "reflect" + "time" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + bpfmanagentinternal "github.com/bpfman/bpfman-operator/controllers/app-agent/internal" + gobpfman "github.com/bpfman/bpfman/clients/gobpfman/v1" + "github.com/go-logr/logr" + "github.com/google/uuid" + "google.golang.org/grpc" +) + +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationstates,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationstates/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationstates/finalizers,verbs=update +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplications/finalizers,verbs=update +// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch +// +kubebuilder:rbac:groups=core,resources=nodes,verbs=get;list;watch +// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get + +const ( + retryDurationAgent = 5 * time.Second +) + +type ReconcilerCommon struct { + client.Client + Scheme *runtime.Scheme + GrpcConn *grpc.ClientConn + BpfmanClient gobpfman.BpfmanClient + Logger logr.Logger + NodeName string + finalizer string + recType string + Containers ContainerGetter + ourNode *v1.Node +} + +type ProgramReconcilerCommon struct { + // ANF-TODO: appCommon is needed to load the program. It won't be needed + // after the load/attch split is ready. + appCommon bpfmaniov1alpha1.BpfAppCommon + currentProgram *bpfmaniov1alpha1.BpfApplicationProgram + currentProgramState *bpfmaniov1alpha1.BpfApplicationProgramState +} + +// ApplicationReconciler is an interface that defines the methods needed to +// reconcile a BpfApplication. +type ApplicationReconciler interface { + // SetupWithManager registers the reconciler with the manager and defines + // which kubernetes events will trigger a reconcile. + SetupWithManager(mgr ctrl.Manager) error + // Reconcile is the main entry point to the reconciler. It will be called by + // the controller runtime when something happens that the reconciler is + // interested in. When Reconcile is invoked, it initializes some state in + // the given bpfmanReconciler, retrieves a list of all programs of the given + // type, and then calls reconcileCommon. + Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) + + getAppStateName() string + getNode() *v1.Node + getNodeSelector() *metav1.LabelSelector + GetStatus() *bpfmaniov1alpha1.BpfAppStatus + isBeingDeleted() bool + updateBpfAppStatus(ctx context.Context, condition metav1.Condition) error + updateLoadStatus(newCondition bpfmaniov1alpha1.BpfProgramConditionType) +} + +// ProgramReconciler is an interface that defines the methods needed to +// reconcile a program contained in a BpfApplication. +type ProgramReconciler interface { + getLoadRequest(mapOwnerId *uint32) (*gobpfman.LoadRequest, error) + getProgId() *uint32 + updateAttachInfo(ctx context.Context, isBeingDeleted bool) error + processAttachInfo(ctx context.Context, mapOwnerStatus *MapOwnerParamStatus) error + shouldAttach() bool + getUUID() string + getAttachId() *uint32 + setAttachId(id *uint32) + setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) bool + getAttachStatus() bpfmaniov1alpha1.BpfProgramConditionType +} + +// ANF-TODO: When we have the load/attach split, this is the function that will +// load or unload the program defined in the BpfApplication. The load will +// return a list of program IDs which will be saved in the node program list. +// For now, just do the following: Update flag saying program should be loaded +// and is loaded. Also, create node program list on the first load. +func (r *ReconcilerCommon) reconcileLoad(rec ApplicationReconciler) error { + isNodeSelected, err := isNodeSelected(rec.getNodeSelector(), rec.getNode().Labels) + if err != nil { + return fmt.Errorf("failed to check if node is selected: %v", err) + } + + // ANF-TODO: When we have the load/attach split, this is where we + // will load/unload the program as necessary. + if !isNodeSelected { + // The program should not be loaded, and should be unloaded if necessary + rec.updateLoadStatus(bpfmaniov1alpha1.BpfProgCondNotSelected) + } else if rec.isBeingDeleted() { + // The program should be unloaded if necessary + rec.updateLoadStatus(bpfmaniov1alpha1.BpfProgCondUnloaded) + } else { + // The program should be loaded, but for now, just set the condition + rec.updateLoadStatus(bpfmaniov1alpha1.BpfProgCondLoaded) + } + + return nil +} + +// ANF-TODO: need better names for differentiating between just updating a +// simple status value and updating a proper Condition. Or, maybe we can just +// set the values direclty. +// +// updateSimpleStatus updates the value of a BpfProgramConditionType. It returns +// a boolean indicating whether the condition was changed. +func updateSimpleStatus(existingCondition *bpfmaniov1alpha1.BpfProgramConditionType, + newCondition bpfmaniov1alpha1.BpfProgramConditionType) bool { + changed := false + if *existingCondition != newCondition { + *existingCondition = newCondition + changed = true + } + return changed +} + +// updateStatus updates the status of a BpfApplication object if needed, +// returning true if the status was changed, and false if the status was not +// changed. +func (r *ReconcilerCommon) updateStatus( + ctx context.Context, + rec ApplicationReconciler, + condition bpfmaniov1alpha1.ProgramConditionType, +) bool { + status := rec.GetStatus() + r.Logger.V(1).Info("updateStatus()", "existing conds", status.Conditions, "new cond", condition) + + if status.Conditions != nil { + numConditions := len(status.Conditions) + + if numConditions == 1 { + if status.Conditions[0].Type == string(condition) { + // No change, so just return false -- not updated + return false + } else { + // We're changing the condition, so delete this one. The + // new condition will be added below. + status.Conditions = nil + } + } else if numConditions > 1 { + // We should only ever have one condition, so we shouldn't hit this + // case. However, if we do, log a message, delete the existing + // conditions, and add the new one below. + r.Logger.Info("more than one BpfProgramCondition", "numConditions", numConditions) + status.Conditions = nil + } + // if numConditions == 0, just add the new condition below. + } + + r.Logger.Info("Calling KubeAPI to update BpfAppState condition", "Name", rec.getAppStateName, "condition", condition.Condition("").Type) + if err := rec.updateBpfAppStatus(ctx, condition.Condition("")); err != nil { + r.Logger.Error(err, "failed to set BpfProgram object status") + } + + r.Logger.V(1).Info("condition updated", "new condition", condition, "existing conds", status.Conditions) + return true +} + +// reconcileProgram is a common function for reconciling programs contained in a +// BpfApplication. It is called by the BpfApplication reconciler for each +// program. It returns a boolean indicating whether anything was changed. +// ANF-TODO: For now, it just supports XDP, but that will be generalized in the +// future. +func (r *ReconcilerCommon) reconcileProgram(ctx context.Context, program ProgramReconciler, isBeingDeleted bool) error { + + mapOwnerStatus, err := r.processMapOwnerParam(ctx, program) + if err != nil { + return err + } + + err = program.updateAttachInfo(ctx, isBeingDeleted) + if err != nil { + return err + } + + err = program.processAttachInfo(ctx, mapOwnerStatus) + if err != nil { + return err + } + + return nil +} + +// get Clientset returns a kubernetes clientset. +func getClientset() (*kubernetes.Clientset, error) { + + // get the in-cluster config + config, err := rest.InClusterConfig() + if err != nil { + return nil, fmt.Errorf("error getting config: %v", err) + } + // create the clientset + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + return nil, fmt.Errorf("error creating clientset: %v", err) + } + + return clientset, nil +} + +func getInterfaces(interfaceSelector *bpfmaniov1alpha1.InterfaceSelector, ourNode *v1.Node) ([]string, error) { + var interfaces []string + + if interfaceSelector.Interfaces != nil { + return *interfaceSelector.Interfaces, nil + } + + if interfaceSelector.PrimaryNodeInterface != nil { + nodeIface, err := bpfmanagentinternal.GetPrimaryNodeInterface(ourNode) + if err != nil { + return nil, err + } + + interfaces = append(interfaces, nodeIface) + return interfaces, nil + } + + return nil, fmt.Errorf("no interfaces selected") +} + +// Only return node updates for our node (all events) +func nodePredicate(nodeName string) predicate.Funcs { + return predicate.Funcs{ + GenericFunc: func(e event.GenericEvent) bool { + return e.Object.GetLabels()["kubernetes.io/hostname"] == nodeName + }, + CreateFunc: func(e event.CreateEvent) bool { + return e.Object.GetLabels()["kubernetes.io/hostname"] == nodeName + }, + UpdateFunc: func(e event.UpdateEvent) bool { + return e.ObjectNew.GetLabels()["kubernetes.io/hostname"] == nodeName + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return e.Object.GetLabels()["kubernetes.io/hostname"] == nodeName + }, + } +} + +// Predicate to watch for Pod events on a specific node which checks if the +// event's Pod is scheduled on the given node. +func podOnNodePredicate(nodeName string) predicate.Funcs { + return predicate.Funcs{ + GenericFunc: func(e event.GenericEvent) bool { + pod, ok := e.Object.(*v1.Pod) + return ok && pod.Spec.NodeName == nodeName + }, + CreateFunc: func(e event.CreateEvent) bool { + pod, ok := e.Object.(*v1.Pod) + return ok && pod.Spec.NodeName == nodeName && pod.Status.Phase == v1.PodRunning + }, + UpdateFunc: func(e event.UpdateEvent) bool { + pod, ok := e.ObjectNew.(*v1.Pod) + return ok && pod.Spec.NodeName == nodeName && pod.Status.Phase == v1.PodRunning + }, + DeleteFunc: func(e event.DeleteEvent) bool { + pod, ok := e.Object.(*v1.Pod) + return ok && pod.Spec.NodeName == nodeName + }, + } +} + +func generateUniqueName(baseName string) string { + uuid := uuid.New().String() + return fmt.Sprintf("%s-%s", baseName, uuid[:8]) +} + +// MapOwnerParamStatus provides the output from a MapOwerSelector being parsed. +type MapOwnerParamStatus struct { + isSet bool + isFound bool + isLoaded bool + mapOwnerId *uint32 +} + +// This function parses the MapOwnerSelector Labor Selector field from the +// BpfProgramCommon struct in the *Program Objects. The labels should map to +// a BpfProgram Object that this *Program wants to share maps with. If found, this +// function returns the ID of the BpfProgram that owns the map on this node. +// Found or not, this function also returns some flags (isSet, isFound, isLoaded) +// to help with the processing and setting of the proper condition on the BpfProgram Object. +func (r *ReconcilerCommon) processMapOwnerParam(ctx context.Context, rec ProgramReconciler) (*MapOwnerParamStatus, error) { + mapOwnerStatus := &MapOwnerParamStatus{ + isSet: false, + isFound: false, + isLoaded: false, + mapOwnerId: nil, + } + + r.Logger.V(1).Info("processMapOwnerParam()", "ctx", ctx, "rec.progId", rec.getProgId(), "MapOwnerStatus", mapOwnerStatus) + + // ANF-TODO: Need to update this to support BpfApplicationState. + return mapOwnerStatus, nil + + // // Parse the MapOwnerSelector label selector. + // mapOwnerSelectorMap, err := metav1.LabelSelectorAsMap(rec.appCommon.MapOwnerSelector) + // if err != nil { + // mapOwnerStatus.isSet = true + // return mapOwnerStatus, fmt.Errorf("failed to parse MapOwnerSelector: %v", err) + // } + + // // If no data was entered, just return with default values, all flags set to false. + // if len(mapOwnerSelectorMap) == 0 { + // return mapOwnerStatus, nil + // } else { + // mapOwnerStatus.isSet = true + + // // Add the labels from the MapOwnerSelector to a map and add an additional + // // label to filter on just this node. Call K8s to find all the eBPF programs + // // that match this filter. + // labelMap := client.MatchingLabels{internal.K8sHostLabel: r.NodeName} + // for key, value := range mapOwnerSelectorMap { + // labelMap[key] = value + // } + // opts := []client.ListOption{labelMap} + // r.Logger.V(1).Info("MapOwner Labels:", "opts", opts) + // bpfProgramList, err := rec.getBpfList(ctx, opts) + // if err != nil { + // return mapOwnerStatus, err + // } + + // // If no BpfProgram Objects were found, or more than one, then return. + // items := (*bpfProgramList).GetItems() + // if len(items) == 0 { + // return mapOwnerStatus, nil + // } else if len(items) > 1 { + // return mapOwnerStatus, fmt.Errorf("MapOwnerSelector resolved to multiple BpfProgram Objects") + // } else { + // mapOwnerStatus.isFound = true + + // // Get bpfProgram based on UID meta + // prog, err := bpfmanagentinternal.GetBpfmanProgram(ctx, r.BpfmanClient, items[0].GetUID()) + // if err != nil { + // return nil, fmt.Errorf("failed to get bpfman program for BpfProgram with UID %s: %v", items[0].GetUID(), err) + // } + + // kernelInfo := prog.GetKernelInfo() + // if kernelInfo == nil { + // return nil, fmt.Errorf("failed to process bpfman program for BpfProgram with UID %s: %v", items[0].GetUID(), err) + // } + // mapOwnerStatus.mapOwnerId = &kernelInfo.Id + + // // Get most recent condition from the one eBPF Program and determine + // // if the BpfProgram is loaded or not. + // conLen := len(items[0].GetStatus().Conditions) + // if conLen > 0 && + // items[0].GetStatus().Conditions[conLen-1].Type == + // string(bpfmaniov1alpha1.BpfProgCondLoaded) { + // mapOwnerStatus.isLoaded = true + // } + + // return mapOwnerStatus, nil + // } + // } +} + +func isNodeSelected(selector *metav1.LabelSelector, nodeLabels map[string]string) (bool, error) { + // Logic to check if this node is selected by the BpfApplication object + selectorTool, err := metav1.LabelSelectorAsSelector(selector) + if err != nil { + return false, fmt.Errorf("failed to parse nodeSelector: %v", + err) + } + + nodeLabelSet, err := labels.ConvertSelectorToLabelsMap(labels.FormatLabels(nodeLabels)) + if err != nil { + return false, fmt.Errorf("failed to parse node labels : %v", + err) + } + + return selectorTool.Matches(nodeLabelSet), nil +} + +// reconcileBpfmanAttachment reconciles the bpfman state for a single +// attachment. It may update attachInfo.AttachInfoCommon.Status and/or +// attachInfo.AttachId. It returns a boolean value indicating whether the +// attachment is no longer needed and should be removed from the list. +// +// ANF-TODO: This function needs to be generalized to handle all program types. +// +// ANF-TODO: When we have load/attach split, this function will just do the +// attach. However, for now, it does the load and attach. +func (r *ReconcilerCommon) reconcileBpfAttachment( + ctx context.Context, + rec ProgramReconciler, + // attachInfo *bpfmaniov1alpha1.XdpAttachInfoState, + loadedBpfPrograms map[string]*gobpfman.ListResponse_ListResult, + // bpfFunctionName string, + mapOwnerStatus *MapOwnerParamStatus) (bool, error) { + + loadedBpfProgram, isAttached := loadedBpfPrograms[string(rec.getUUID())] + + r.Logger.V(1).Info("reconcileBpfAttachment()", "shouldAttached", rec.shouldAttach(), "isAttached", isAttached) + + switch rec.shouldAttach() { + case true: + switch isAttached { + case true: + // The program is attached and it should be attached. + // prog ID should already have been set if program is attached + if !reflect.DeepEqual(rec.getAttachId(), &loadedBpfProgram.KernelInfo.Id) { + // This shouldn't happen, but if it does, log a message and update AttachId. + r.Logger.V(1).Info("ID mismatch. Updating", "Saved ID", rec.getAttachId(), + "Kernel ID", loadedBpfProgram.KernelInfo.Id) + rec.setAttachId(&loadedBpfProgram.KernelInfo.Id) + } + // Confirm it's in the correct state. + loadRequest, err := rec.getLoadRequest(mapOwnerStatus.mapOwnerId) + if err != nil { + r.Logger.Error(err, "Failed to get LoadRequest") + if rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondBytecodeSelectorError) { + return false, err + } + } else { + r.Logger.Info("LoadRequest", "loadRequest", loadRequest) + isSame, reasons := bpfmanagentinternal.DoesProgExist(loadedBpfProgram, loadRequest) + if !isSame { + r.Logger.Info("Attachment is in wrong state, detach and re-attach", "reason", reasons, "Attach ID", rec.getAttachId()) + err := bpfmanagentinternal.UnloadBpfmanProgram(ctx, r.BpfmanClient, *rec.getAttachId()) + if err != nil { + r.Logger.Error(err, "Failed to detach eBPF Program") + if rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotUnloaded) { + return false, err + } + } else { + r.Logger.Info("Calling bpfman to attach eBPF Program") + attachId, err := bpfmanagentinternal.LoadBpfmanProgram(ctx, r.BpfmanClient, loadRequest) + if err != nil { + r.Logger.Error(err, "Failed to attach eBPF Program") + if rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotLoaded) { + return false, err + + } + } else { + rec.setAttachId(attachId) + rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondAttached) + } + } + } else { + // Attachment exists and bpfProgram K8s Object is up to date + r.Logger.V(1).Info("Attachment is in correct state. Nothing to do in bpfman") + rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondAttached) + } + } + case false: + // The program should be attached, but it isn't. + r.Logger.Info("Program is not attached, calling getLoadRequest()") + loadRequest, err := rec.getLoadRequest(mapOwnerStatus.mapOwnerId) + if err != nil { + r.Logger.Error(err, "Failed to get LoadRequest") + if rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondBytecodeSelectorError) { + return false, err + } + } else { + r.Logger.Info("LoadRequest", "loadRequest", loadRequest) + r.Logger.Info("Calling bpfman to attach eBPF Program on node") + attachId, err := bpfmanagentinternal.LoadBpfmanProgram(ctx, r.BpfmanClient, loadRequest) + if err != nil { + r.Logger.Error(err, "Failed to attach eBPF Program") + if rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotLoaded) { + return false, err + } + } else { + rec.setAttachId(attachId) + rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondAttached) + } + } + } + case false: + switch isAttached { + case true: + // The program is attached but it shouldn't be attached. Unload it. + r.Logger.Info("Calling bpfman to detach eBPF Program", "Attach ID", rec.getAttachId()) + if err := bpfmanagentinternal.UnloadBpfmanProgram(ctx, r.BpfmanClient, *rec.getAttachId()); err != nil { + r.Logger.Error(err, "Failed to detach eBPF Program") + if rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotUnloaded) { + return false, err + } + } else { + rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotAttached) + } + case false: + // The program shouldn't be attached and it isn't. + rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotAttached) + } + } + + // The BPF program was successfully reconciled. + remove := !rec.shouldAttach() && rec.getAttachStatus() == bpfmaniov1alpha1.BpfProgCondNotAttached + return remove, nil +} + +// removeFinalizer removes the finalizer from the object if is applied, +// returning if the action resulted in a kube API update or not along with any +// errors. +func (r *ReconcilerCommon) removeFinalizer(ctx context.Context, o client.Object, finalizer string) bool { + changed := controllerutil.RemoveFinalizer(o, finalizer) + if changed { + r.Logger.Info("Calling KubeAPI to remove finalizer from BpfProgram", "object name", o.GetName()) + err := r.Update(ctx, o) + if err != nil { + r.Logger.Error(err, "failed to remove BpfProgram Finalizer") + return true + } + } + + return changed +} diff --git a/controllers/app-agent/containers.go b/controllers/app-agent/containers.go new file mode 100644 index 000000000..ab3a1651d --- /dev/null +++ b/controllers/app-agent/containers.go @@ -0,0 +1,252 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +*/ + +package appagent + +import ( + "context" + "fmt" + "os/exec" + "slices" + "strconv" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + + "github.com/buger/jsonparser" + "github.com/go-logr/logr" +) + +type ContainerInfo struct { + podName string + containerName string + pid int64 +} + +// Create an interface for getting the list of containers in which the program +// should be attached so we can mock it in unit tests. +type ContainerGetter interface { + // Get the list of containers on this node that match the containerSelector. + GetContainers(ctx context.Context, + selectorNamespace string, + selectorPods metav1.LabelSelector, + selectorContainerNames *[]string, + logger logr.Logger) (*[]ContainerInfo, error) +} + +type RealContainerGetter struct { + nodeName string + clientSet kubernetes.Interface +} + +func NewRealContainerGetter(nodeName string) (*RealContainerGetter, error) { + clientSet, err := getClientset() + if err != nil { + return nil, fmt.Errorf("failed to get clientset: %v", err) + } + + containerGetter := RealContainerGetter{ + nodeName: nodeName, + clientSet: clientSet, + } + + return &containerGetter, nil +} + +func (c *RealContainerGetter) GetContainers( + ctx context.Context, + selectorNamespace string, + selectorPods metav1.LabelSelector, + selectorContainerNames *[]string, + logger logr.Logger) (*[]ContainerInfo, error) { + + // Get the list of pods that match the selector. + podList, err := c.getPodsForNode(ctx, selectorNamespace, selectorPods) + if err != nil { + return nil, fmt.Errorf("failed to get pod list: %v", err) + } + + // Get the list of containers in the list of pods that match the selector. + containerList, err := getContainerInfo(podList, selectorContainerNames, logger) + if err != nil { + return nil, fmt.Errorf("failed to get container info: %v", err) + } + + logger.V(1).Info("from getContainerInfo", "containers", containerList) + + return containerList, nil +} + +// getPodsForNode returns a list of pods on the given node that match the given +// container selector. +func (c *RealContainerGetter) getPodsForNode( + ctx context.Context, + selectorNamespace string, + selectorPods metav1.LabelSelector, +) (*v1.PodList, error) { + + selectorString := metav1.FormatLabelSelector(&selectorPods) + + if selectorString == "" { + return nil, fmt.Errorf("error parsing selector: %v", selectorString) + } + + listOptions := metav1.ListOptions{ + FieldSelector: "spec.nodeName=" + c.nodeName, + } + + if selectorString != "" { + listOptions.LabelSelector = selectorString + } + + podList, err := c.clientSet.CoreV1().Pods(selectorNamespace).List(ctx, listOptions) + if err != nil { + return nil, fmt.Errorf("error getting pod list: %v", err) + } + + return podList, nil +} + +// getContainerInfo returns a list of containerInfo for the given pod list and container names. +func getContainerInfo(podList *v1.PodList, containerNames *[]string, logger logr.Logger) (*[]ContainerInfo, error) { + + crictl := "/usr/local/bin/crictl" + + containers := []ContainerInfo{} + + for i, pod := range podList.Items { + logger.V(1).Info("Pod", "index", i, "Name", pod.Name, "Namespace", pod.Namespace, "NodeName", pod.Spec.NodeName) + + // Find the unique Pod ID of the given pod. + cmd := exec.Command(crictl, "pods", "--name", pod.Name, "-o", "json") + podInfo, err := cmd.Output() + if err != nil { + logger.Info("Failed to get pod info", "error", err) + return nil, err + } + + // The crictl --name option works like a grep on the names of pods. + // Since we are using the unique name of the pod generated by k8s, we + // will most likely only get one pod. Though very unlikely, it is + // technically possible that this unique name is a substring of another + // pod name. If that happens, we would get multiple pods, so we handle + // that possibility with the following for loop. + var podId string + podFound := false + for podIndex := 0; ; podIndex++ { + indexString := "[" + strconv.Itoa(podIndex) + "]" + podId, err = jsonparser.GetString(podInfo, "items", indexString, "id") + if err != nil { + // We hit the end of the list of pods and didn't find it. This + // should only happen if the pod was deleted between the time we + // got the list of pods and the time we got the info about the + // pod. + break + } + podName, err := jsonparser.GetString(podInfo, "items", indexString, "metadata", "name") + if err != nil { + // We shouldn't get an error here if we didn't get an error + // above, but just in case... + logger.Error(err, "Error getting pod name") + break + } + + if podName == pod.Name { + podFound = true + break + } + } + + if !podFound { + return nil, fmt.Errorf("pod %s not found in crictl pod list", pod.Name) + } + + logger.V(1).Info("podFound", "podId", podId, "err", err) + + // Get info about the containers in the pod so we can get their unique IDs. + cmd = exec.Command(crictl, "ps", "--pod", podId, "-o", "json") + containerData, err := cmd.Output() + if err != nil { + logger.Info("Failed to get container info", "error", err) + return nil, err + } + + // For each container in the pod... + for containerIndex := 0; ; containerIndex++ { + + indexString := "[" + strconv.Itoa(containerIndex) + "]" + + // Make sure the container name is in the list of containers we want. + containerName, err := jsonparser.GetString(containerData, "containers", indexString, "metadata", "name") + if err != nil { + break + } + + if containerNames != nil && + len(*containerNames) > 0 && + !slices.Contains((*containerNames), containerName) { + continue + } + + // If it is in the list, get the container ID. + containerId, err := jsonparser.GetString(containerData, "containers", indexString, "id") + if err != nil { + break + } + + // Now use the container ID to get more info about the container so + // we can get the PID. + cmd = exec.Command(crictl, "inspect", "-o", "json", containerId) + containerData, err := cmd.Output() + if err != nil { + logger.Info("Failed to get container data", "error", err) + continue + } + containerPid, err := jsonparser.GetInt(containerData, "info", "pid") + if err != nil { + logger.Info("Failed to get container PID", "error", err) + continue + } + + container := ContainerInfo{ + podName: pod.Name, + containerName: containerName, + pid: containerPid, + } + + containers = append(containers, container) + } + + } + + return &containers, nil +} + +// // Check if the annotation is set to indicate that no containers on this node +// // matched the container selector. +// func noContainersOnNode[T BpfProg](bpfProgram *T, annotationIndex string) bool { +// if bpfProgram == nil { +// return false +// } + +// annotations := (*bpfProgram).GetAnnotations() +// noContainersOnNode, ok := annotations[annotationIndex] +// if ok && noContainersOnNode == "true" { +// return true +// } + +// return false +// } diff --git a/controllers/app-agent/internal/auth.go b/controllers/app-agent/internal/auth.go new file mode 100644 index 000000000..b44819372 --- /dev/null +++ b/controllers/app-agent/internal/auth.go @@ -0,0 +1,144 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "strings" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// ContainerConfigJSON represents ~/.docker/config.json file info +// See https://github.com/docker/docker/pull/12009 +// Structure from https://github.com/kubernetes/kubernetes/blob/master/pkg/credentialprovider/config.go#L39 +type ContainerConfigJSON struct { + Auths ContainerConfig `json:"auths"` + // +optional + HTTPHeaders map[string]string `json:"HttpHeaders,omitempty"` +} + +// DockerConfig represents the config file used by the docker CLI. +// This config that represents the credentials that should be used +// when pulling images from specific image repositories. +type ContainerConfig map[string]ContainerConfigEntry + +// ContainerConfigEntry wraps a container config as a entry +type ContainerConfigEntry struct { + Username string + Password string + Email string +} + +// dockerConfigEntryWithAuth is used solely for deserializing the Auth field +// into a dockerConfigEntry during JSON deserialization. +type ContainerConfigEntryWithAuth struct { + // +optional + Username string `json:"username,omitempty"` + // +optional + Password string `json:"password,omitempty"` + // +optional + Email string `json:"email,omitempty"` + // +optional + Auth string `json:"auth,omitempty"` +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (ident *ContainerConfigEntry) UnmarshalJSON(data []byte) error { + var tmp ContainerConfigEntryWithAuth + err := json.Unmarshal(data, &tmp) + if err != nil { + return err + } + + if len(tmp.Auth) == 0 { + return nil + } + + ident.Username, ident.Password, err = decodeContainerConfigFieldAuth(tmp.Auth) + return err +} + +// decodeContainerConfigFieldAuth deserializes the "auth" field from containercfg into a +// username and a password. The format of the auth field is base64(:). +func decodeContainerConfigFieldAuth(field string) (username, password string, err error) { + + var decoded []byte + + // StdEncoding can only decode padded string + // RawStdEncoding can only decode unpadded string + if strings.HasSuffix(strings.TrimSpace(field), "=") { + // decode padded data + decoded, err = base64.StdEncoding.DecodeString(field) + } else { + // decode unpadded data + decoded, err = base64.RawStdEncoding.DecodeString(field) + } + + if err != nil { + return + } + + parts := strings.SplitN(string(decoded), ":", 2) + if len(parts) != 2 { + err = fmt.Errorf("unable to parse auth field, must be formatted as base64(username:password)") + return + } + + username = parts[0] + password = parts[1] + + return +} + +// Mimicking exactly what Kubernetes does to pull out auths from secrets: +// https://github.com/kubernetes/kubernetes/blob/master/pkg/credentialprovider/secrets/secrets.go#L29 +func ParseAuth(c client.Client, secretName, secretNamespace string) (*ContainerConfig, error) { + var creds ContainerConfig + + // Lookup the k8s Secret for repository authentication + ctx := context.TODO() + imageSecret := &v1.Secret{} + + if err := c.Get(ctx, types.NamespacedName{Namespace: secretNamespace, Name: secretName}, imageSecret); err != nil { + return nil, fmt.Errorf("failed image auth secret %s: %v", + secretName, err) + } + + if containerConfigJSONBytes, containerConfigJSONExists := imageSecret.Data[v1.DockerConfigJsonKey]; (imageSecret.Type == v1.SecretTypeDockerConfigJson) && containerConfigJSONExists && (len(containerConfigJSONBytes) > 0) { + containerConfigJSON := ContainerConfigJSON{} + if err := json.Unmarshal(containerConfigJSONBytes, &containerConfigJSON); err != nil { + return nil, err + } + + creds = containerConfigJSON.Auths + } else if dockercfgBytes, dockercfgExists := imageSecret.Data[v1.DockerConfigKey]; (imageSecret.Type == v1.SecretTypeDockercfg) && dockercfgExists && (len(dockercfgBytes) > 0) { + dockercfg := ContainerConfig{} + if err := json.Unmarshal(dockercfgBytes, &dockercfg); err != nil { + return nil, err + } + + creds = dockercfg + } + + return &creds, nil +} diff --git a/controllers/app-agent/internal/bpfman-core.go b/controllers/app-agent/internal/bpfman-core.go new file mode 100644 index 000000000..6223f078a --- /dev/null +++ b/controllers/app-agent/internal/bpfman-core.go @@ -0,0 +1,206 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "context" + "fmt" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + "github.com/bpfman/bpfman-operator/internal" + gobpfman "github.com/bpfman/bpfman/clients/gobpfman/v1" + "github.com/containers/image/v5/docker/reference" + + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var log = ctrl.Log.WithName("agent-intern") + +func imagePullPolicyConversion(policy bpfmaniov1alpha1.PullPolicy) int32 { + switch policy { + case bpfmaniov1alpha1.PullAlways: + return 0 + case bpfmaniov1alpha1.PullIfNotPresent: + return 1 + case bpfmaniov1alpha1.PullNever: + return 2 + default: + return 1 + } +} + +func GetBytecode(c client.Client, b *bpfmaniov1alpha1.BytecodeSelector) (*gobpfman.BytecodeLocation, error) { + if b.Image != nil { + bytecodeImage := b.Image + + ref, err := reference.ParseNamed(bytecodeImage.Url) + if err != nil { + return nil, err + } + + var username, password string + if bytecodeImage.ImagePullSecret != nil { + creds, err := ParseAuth(c, bytecodeImage.ImagePullSecret.Name, bytecodeImage.ImagePullSecret.Namespace) + if err != nil { + return nil, err + } + + if creds == nil { + return nil, fmt.Errorf("no registry credentials found in secret: %s", bytecodeImage.ImagePullSecret) + } + + domain := reference.Domain(ref) + + // All docker.io image domains resolve to https://index.docker.io/v1/ in the credentials JSON file. + if domain == "docker.io" || domain == "" { + domain = "https://index.docker.io/v1/" + } + + cred := (*creds)[domain] + + username = cred.Username + password = cred.Password + } + + return &gobpfman.BytecodeLocation{ + Location: &gobpfman.BytecodeLocation_Image{Image: &gobpfman.BytecodeImage{ + Url: bytecodeImage.Url, + ImagePullPolicy: imagePullPolicyConversion(bytecodeImage.ImagePullPolicy), + Username: &username, + Password: &password, + }}, + }, nil + } else { + return &gobpfman.BytecodeLocation{ + Location: &gobpfman.BytecodeLocation_File{File: *b.Path}, + }, nil + } +} + +func buildBpfmanUnloadRequest(id uint32) *gobpfman.UnloadRequest { + return &gobpfman.UnloadRequest{ + Id: id, + } +} + +func LoadBpfmanProgram(ctx context.Context, bpfmanClient gobpfman.BpfmanClient, + loadRequest *gobpfman.LoadRequest) (*uint32, error) { + var res *gobpfman.LoadResponse + + res, err := bpfmanClient.Load(ctx, loadRequest) + if err != nil { + return nil, fmt.Errorf("failed to load bpfProgram via bpfman: %w", err) + } + kernelInfo := res.GetKernelInfo() + if kernelInfo == nil { + return nil, fmt.Errorf("no kernel info for load bpfProgram") + } + id := kernelInfo.GetId() + + return &id, nil +} + +func UnloadBpfmanProgram(ctx context.Context, bpfmanClient gobpfman.BpfmanClient, id uint32) error { + _, err := bpfmanClient.Unload(ctx, buildBpfmanUnloadRequest(id)) + if err != nil { + return fmt.Errorf("failed to unload bpfProgram via bpfman: %v", + err) + } + return nil +} + +func ListBpfmanPrograms(ctx context.Context, bpfmanClient gobpfman.BpfmanClient, programType internal.ProgramType) (map[string]*gobpfman.ListResponse_ListResult, error) { + listOnlyBpfmanPrograms := true + listReq := gobpfman.ListRequest{ + ProgramType: programType.Uint32(), + BpfmanProgramsOnly: &listOnlyBpfmanPrograms, + } + + out := map[string]*gobpfman.ListResponse_ListResult{} + + listResponse, err := bpfmanClient.List(ctx, &listReq) + if err != nil { + return nil, err + } + + for _, result := range listResponse.Results { + info := result.GetInfo() + if info != nil { + metadata := info.GetMetadata() + if uuid, ok := metadata[internal.UuidMetadataKey]; ok { + out[uuid] = result + } else { + return nil, fmt.Errorf("unable to get uuid from program metadata") + } + } + } + + return out, nil +} + +func GetBpfmanProgram(ctx context.Context, bpfmanClient gobpfman.BpfmanClient, uuid types.UID) (*gobpfman.ListResponse_ListResult, error) { + listReq := gobpfman.ListRequest{ + MatchMetadata: map[string]string{internal.UuidMetadataKey: string(uuid)}, + } + + listResponse, err := bpfmanClient.List(ctx, &listReq) + if err != nil { + return nil, err + } + + if len(listResponse.Results) == 0 { + return nil, fmt.Errorf("unable to find program for uuid: %+v ", uuid) + } else if len(listResponse.Results) != 1 { + return nil, fmt.Errorf("multiple programs found for uuid: %+v instances: %d", uuid, len(listResponse.Results)) + } + + return listResponse.Results[0], nil +} + +func ListAllPrograms(ctx context.Context, bpfmanClient gobpfman.BpfmanClient) ([]*gobpfman.ListResponse_ListResult, error) { + listResponse, err := bpfmanClient.List(ctx, &gobpfman.ListRequest{}) + if err != nil { + return nil, err + } + + return listResponse.Results, nil +} + +// Convert a list result into a set of kernel info annotations +func Build_kernel_info_annotations(p *gobpfman.ListResponse_ListResult) map[string]string { + kernelInfo := p.GetKernelInfo() + if kernelInfo != nil { + return map[string]string{ + "Kernel-ID": fmt.Sprint(kernelInfo.GetId()), + "Name": kernelInfo.GetName(), + "Type": internal.ProgramType(kernelInfo.GetProgramType()).String(), + "Loaded-At": kernelInfo.GetLoadedAt(), + "Tag": kernelInfo.GetTag(), + "GPL-Compatible": fmt.Sprintf("%v", kernelInfo.GetGplCompatible()), + "Map-IDs": fmt.Sprintf("%v", kernelInfo.GetMapIds()), + "BTF-ID": fmt.Sprint(kernelInfo.GetBtfId()), + "Size-Translated-Bytes": fmt.Sprint(kernelInfo.GetBytesXlated()), + "JITed": fmt.Sprintf("%v", kernelInfo.GetJited()), + "Size-JITed-Bytes": fmt.Sprint(kernelInfo.GetBytesJited()), + "Kernel-Allocated-Memory-Bytes": fmt.Sprint(kernelInfo.GetBytesMemlock()), + "Verified-Instruction-Count": fmt.Sprint(kernelInfo.GetVerifiedInsns()), + } + } + return nil +} diff --git a/controllers/app-agent/internal/cmp.go b/controllers/app-agent/internal/cmp.go new file mode 100644 index 000000000..b36234b81 --- /dev/null +++ b/controllers/app-agent/internal/cmp.go @@ -0,0 +1,183 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "fmt" + "reflect" + + gobpfman "github.com/bpfman/bpfman/clients/gobpfman/v1" +) + +// Look at using https://pkg.go.dev/google.golang.org/protobuf/testing/protocmp to simplify. +// Is state equal, ignoring UUID and GRPC type fields. +func DoesProgExist(actual *gobpfman.ListResponse_ListResult, expected *gobpfman.LoadRequest) (bool, []string) { + var reasons []string + + actualInfo := actual.GetInfo() + if actualInfo == nil { + reasons = append(reasons, "Missing response data") + return true, reasons + } + + actualKernelInfo := actual.GetKernelInfo() + if actualKernelInfo == nil { + reasons = append(reasons, "Missing kernel response data") + return true, reasons + } + + // Check equality of all common fields + actualMeta := actualInfo.GetMetadata() + expectedMeta := expected.GetMetadata() + if !reflect.DeepEqual(actualMeta, expectedMeta) { + reasons = append(reasons, fmt.Sprintf("Expected ID to be %v but found %v", + actualMeta, expectedMeta)) + } + + actualName := actualInfo.GetName() + expectedBpfFunctionName := expected.GetName() + if actualName != expectedBpfFunctionName { + reasons = append(reasons, fmt.Sprintf("Expected Name to be %s but found %s", + expectedBpfFunctionName, actualName)) + } + + actualProgramType := actualKernelInfo.GetProgramType() + expectedProgramType := expected.GetProgramType() + if actualProgramType != expectedProgramType { + reasons = append(reasons, fmt.Sprintf("Expected ProgramType to be %d but found %d", + expectedProgramType, actualProgramType)) + } + + // Check equality of all bytecode location fields + actualBytecode := actualInfo.GetBytecode() + expectedBytecode := expected.GetBytecode() + if actualBytecode != nil && expectedBytecode != nil { + actualImage := actualBytecode.GetImage() + expectedImage := expectedBytecode.GetImage() + if actualImage != nil && expectedImage != nil { + if actualImage.Url != expectedImage.Url { + reasons = append(reasons, fmt.Sprintf("Expected Image URL to be %s but found %s", + expectedImage.Url, actualImage.Url)) + } + if actualImage.ImagePullPolicy != expectedImage.ImagePullPolicy { + reasons = append(reasons, fmt.Sprintf("Expected ImagePullPolicy to be %d but found %d", + expectedImage.ImagePullPolicy, actualImage.ImagePullPolicy)) + } + } + + actualFile := actualBytecode.GetFile() + expectedFile := expectedBytecode.GetFile() + if actualFile != expectedFile { + reasons = append(reasons, fmt.Sprintf("Expected File to be %s but found %s", + expectedFile, actualFile)) + } + } + + // Check equality of Map Owner + actualMapOwnerId := actualInfo.GetMapOwnerId() + expectedMapOwnerId := expected.GetMapOwnerId() + if actualMapOwnerId != expectedMapOwnerId { + reasons = append(reasons, fmt.Sprintf("Expected File to be %d but found %d", + expectedMapOwnerId, actualMapOwnerId)) + } + + // Check equality of program specific fields + actualAttach := actualInfo.GetAttach() + expectedAttach := expected.GetAttach() + if actualAttach != nil && expectedAttach != nil { + actualXdp := actualAttach.GetXdpAttachInfo() + expectedXdp := expectedAttach.GetXdpAttachInfo() + if actualXdp != nil && expectedXdp != nil { + if actualXdp.Priority != expectedXdp.Priority || + actualXdp.Iface != expectedXdp.Iface || + !reflect.DeepEqual(actualXdp.ProceedOn, expectedXdp.ProceedOn) { + reasons = append(reasons, fmt.Sprintf("Expected XDP to be %v but found %v", + expectedXdp, actualXdp)) + } + } + + actualTc := actualAttach.GetTcAttachInfo() + expectedTc := expectedAttach.GetTcAttachInfo() + if actualTc != nil && expectedTc != nil { + if actualTc.Priority != expectedTc.Priority || + actualTc.Iface != expectedTc.Iface || + !reflect.DeepEqual(actualTc.ProceedOn, expectedTc.ProceedOn) { + reasons = append(reasons, fmt.Sprintf("Expected TC to be %v but found %v", + expectedTc, actualTc)) + } + } + + actualTracepoint := actualAttach.GetTracepointAttachInfo() + expectedTracepoint := expectedAttach.GetTracepointAttachInfo() + if actualTracepoint != nil && expectedTracepoint != nil { + if actualTracepoint.Tracepoint != expectedTracepoint.Tracepoint { + reasons = append(reasons, fmt.Sprintf("Expected Tracepoint to be %v but found %v", + expectedTracepoint, actualTracepoint)) + } + } + + actualKprobe := actualAttach.GetKprobeAttachInfo() + expectedKprobe := expectedAttach.GetKprobeAttachInfo() + if actualKprobe != nil && expectedKprobe != nil { + if actualKprobe.FnName != expectedKprobe.FnName || + actualKprobe.Offset != expectedKprobe.Offset || + actualKprobe.Retprobe != expectedKprobe.Retprobe || + !reflect.DeepEqual(actualKprobe.ContainerPid, expectedKprobe.ContainerPid) { + reasons = append(reasons, fmt.Sprintf("Expected Kprobe to be %v but found %v", + expectedKprobe, actualKprobe)) + } + } + + actualUprobe := actualAttach.GetUprobeAttachInfo() + expectedUprobe := expectedAttach.GetUprobeAttachInfo() + if actualUprobe != nil && expectedUprobe != nil { + if !reflect.DeepEqual(actualUprobe.FnName, expectedUprobe.FnName) || + actualUprobe.Offset != expectedUprobe.Offset || + actualUprobe.Target != expectedUprobe.Target || + actualUprobe.Retprobe != expectedUprobe.Retprobe || + actualUprobe.Pid != expectedUprobe.Pid || + !reflect.DeepEqual(actualUprobe.ContainerPid, expectedUprobe.ContainerPid) { + reasons = append(reasons, fmt.Sprintf("Expected Uprobe to be %v but found %v", + expectedUprobe, actualUprobe)) + } + } + + actualFentry := actualAttach.GetFentryAttachInfo() + expectedFentry := expectedAttach.GetFentryAttachInfo() + if actualFentry != nil && expectedFentry != nil { + if !reflect.DeepEqual(actualFentry.FnName, expectedFentry.FnName) { + reasons = append(reasons, fmt.Sprintf("Expected Fentry to be %v but found %v", + expectedFentry, actualFentry)) + } + } + + actualFexit := actualAttach.GetFexitAttachInfo() + expectedFexit := expectedAttach.GetFexitAttachInfo() + if actualFexit != nil && expectedFexit != nil { + if !reflect.DeepEqual(actualFexit.FnName, expectedFexit.FnName) { + reasons = append(reasons, fmt.Sprintf("Expected Fexit to be %v but found %v", + expectedFexit, actualFexit)) + } + } + } + + if len(reasons) == 0 { + return true, reasons + } else { + return false, reasons + } +} diff --git a/controllers/app-agent/internal/iface.go b/controllers/app-agent/internal/iface.go new file mode 100644 index 000000000..631087ca1 --- /dev/null +++ b/controllers/app-agent/internal/iface.go @@ -0,0 +1,63 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "fmt" + "net" + + v1 "k8s.io/api/core/v1" +) + +func GetPrimaryNodeInterface(ourNode *v1.Node) (string, error) { + ifaces, err := net.Interfaces() + if err != nil { + return "", fmt.Errorf("failed to read node interfaces: %v", err) + } + + for _, ipaddr := range ourNode.Status.Addresses { + log.V(2).Info("Node IP - ", "Type", ipaddr.Type, "Address", ipaddr.Address) + if ipaddr.Type == v1.NodeInternalIP { + for _, i := range ifaces { + addrs, err := i.Addrs() + if err != nil { + log.Error(err, "failed to parse localAddresses, continuing") + continue + } + for _, a := range addrs { + switch v := a.(type) { + case *net.IPAddr: + log.V(2).Info("localAddresses", "name", i.Name, "index", i.Index, "addr", v, "mask", v.IP.DefaultMask()) + if ipaddr.Address == v.String() { + log.V(1).Info("primary node interface set", "name", i.Name) + return i.Name, nil + } + + case *net.IPNet: + log.V(2).Info(" localAddresses", "name", i.Name, "index", i.Index, "v", v, "addr", v.IP, "mask", v.Mask) + if v.IP.Equal(net.ParseIP(ipaddr.Address)) { + log.V(1).Info("primary node interface set", "name", i.Name) + return i.Name, nil + } + } + } + } + } + } + + return "", fmt.Errorf("unable to find Node Interface") +} diff --git a/controllers/app-agent/internal/test-utils/fake_bpfman_client.go b/controllers/app-agent/internal/test-utils/fake_bpfman_client.go new file mode 100644 index 000000000..8e7bf1261 --- /dev/null +++ b/controllers/app-agent/internal/test-utils/fake_bpfman_client.go @@ -0,0 +1,120 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testutils + +import ( + "context" + "fmt" + "math/rand" + + gobpfman "github.com/bpfman/bpfman/clients/gobpfman/v1" + grpc "google.golang.org/grpc" +) + +type BpfmanClientFake struct { + LoadRequests map[int]*gobpfman.LoadRequest + UnloadRequests map[int]*gobpfman.UnloadRequest + ListRequests []*gobpfman.ListRequest + GetRequests map[int]*gobpfman.GetRequest + Programs map[int]*gobpfman.ListResponse_ListResult + PullBytecodeRequests map[int]*gobpfman.PullBytecodeRequest +} + +func NewBpfmanClientFake() *BpfmanClientFake { + return &BpfmanClientFake{ + LoadRequests: map[int]*gobpfman.LoadRequest{}, + UnloadRequests: map[int]*gobpfman.UnloadRequest{}, + ListRequests: []*gobpfman.ListRequest{}, + GetRequests: map[int]*gobpfman.GetRequest{}, + Programs: map[int]*gobpfman.ListResponse_ListResult{}, + PullBytecodeRequests: map[int]*gobpfman.PullBytecodeRequest{}, + } +} + +func NewBpfmanClientFakeWithPrograms(programs map[int]*gobpfman.ListResponse_ListResult) *BpfmanClientFake { + return &BpfmanClientFake{ + LoadRequests: map[int]*gobpfman.LoadRequest{}, + UnloadRequests: map[int]*gobpfman.UnloadRequest{}, + ListRequests: []*gobpfman.ListRequest{}, + GetRequests: map[int]*gobpfman.GetRequest{}, + Programs: programs, + } +} + +func (b *BpfmanClientFake) Load(ctx context.Context, in *gobpfman.LoadRequest, opts ...grpc.CallOption) (*gobpfman.LoadResponse, error) { + id := rand.Intn(100) + b.LoadRequests[id] = in + + b.Programs[id] = loadRequestToListResult(in, uint32(id)) + + return &gobpfman.LoadResponse{ + Info: b.Programs[id].Info, + KernelInfo: b.Programs[id].KernelInfo, + }, nil +} + +func (b *BpfmanClientFake) Unload(ctx context.Context, in *gobpfman.UnloadRequest, opts ...grpc.CallOption) (*gobpfman.UnloadResponse, error) { + b.UnloadRequests[int(in.Id)] = in + delete(b.Programs, int(in.Id)) + + return &gobpfman.UnloadResponse{}, nil +} + +func (b *BpfmanClientFake) List(ctx context.Context, in *gobpfman.ListRequest, opts ...grpc.CallOption) (*gobpfman.ListResponse, error) { + b.ListRequests = append(b.ListRequests, in) + results := &gobpfman.ListResponse{Results: []*gobpfman.ListResponse_ListResult{}} + for _, v := range b.Programs { + results.Results = append(results.Results, v) + } + return results, nil +} + +func loadRequestToListResult(loadReq *gobpfman.LoadRequest, id uint32) *gobpfman.ListResponse_ListResult { + mapOwnerId := loadReq.GetMapOwnerId() + programInfo := gobpfman.ProgramInfo{ + Name: loadReq.GetName(), + Bytecode: loadReq.GetBytecode(), + Attach: loadReq.GetAttach(), + GlobalData: loadReq.GetGlobalData(), + MapOwnerId: &mapOwnerId, + Metadata: loadReq.GetMetadata(), + } + kernelInfo := gobpfman.KernelProgramInfo{ + Id: id, + ProgramType: loadReq.GetProgramType(), + } + + return &gobpfman.ListResponse_ListResult{ + Info: &programInfo, + KernelInfo: &kernelInfo, + } +} + +func (b *BpfmanClientFake) Get(ctx context.Context, in *gobpfman.GetRequest, opts ...grpc.CallOption) (*gobpfman.GetResponse, error) { + if b.Programs[int(in.Id)] != nil { + return &gobpfman.GetResponse{ + Info: b.Programs[int(in.Id)].Info, + KernelInfo: b.Programs[int(in.Id)].KernelInfo, + }, nil + } else { + return nil, fmt.Errorf("Requested program does not exist") + } +} + +func (b *BpfmanClientFake) PullBytecode(ctx context.Context, in *gobpfman.PullBytecodeRequest, opts ...grpc.CallOption) (*gobpfman.PullBytecodeResponse, error) { + return &gobpfman.PullBytecodeResponse{}, nil +} diff --git a/controllers/app-operator/application-cl-program_test.go b/controllers/app-operator/application-cl-program_test.go new file mode 100644 index 000000000..06c376add --- /dev/null +++ b/controllers/app-operator/application-cl-program_test.go @@ -0,0 +1,264 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package appoperator + +import ( + "context" + "fmt" + "testing" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + internal "github.com/bpfman/bpfman-operator/internal" + testutils "github.com/bpfman/bpfman-operator/internal/test-utils" + + "github.com/stretchr/testify/require" + meta "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" +) + +// Runs the ApplicationProgramReconcile test. If multiCondition == true, it runs it +// with an error case in which the program object has multiple conditions. +func appProgramReconcile(t *testing.T, multiCondition bool) { + var ( + bpfAppName = "fakeAppProgram" + bytecodePath = "/tmp/hello.o" + xdpBpfFunctionName = "XdpTest" + fakeNode = testutils.NewNode("fake-control-plane") + ctx = context.TODO() + bpfAppStateName = fmt.Sprintf("%s-%s", bpfAppName, "12345") + xdpPriority = 50 + fakeInt0 = "eth0" + // bpfFentryFunctionName = "fentry_test" + // bpfKprobeFunctionName = "kprobe_test" + // bpfTracepointFunctionName = "tracepoint-test" + // functionFentryName = "do_unlinkat" + // functionKprobeName = "try_to_wake_up" + // tracepointName = "syscalls/sys_enter_setitimer" + // offset = 0 + // retprobe = false + ) + + fakeInts := []string{fakeInt0} + + interfaceSelector := bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &fakeInts, + } + + proceedOn := []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), + bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return")} + + attachInfo := bpfmaniov1alpha1.XdpAttachInfo{ + InterfaceSelector: interfaceSelector, + Containers: nil, + Priority: int32(xdpPriority), + ProceedOn: proceedOn, + } + + programs := []bpfmaniov1alpha1.BpfApplicationProgram{} + + xdpProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: xdpBpfFunctionName, + }, + Type: bpfmaniov1alpha1.ProgTypeXDP, + XDP: &bpfmaniov1alpha1.XdpProgramInfo{ + AttachPoints: []bpfmaniov1alpha1.XdpAttachInfo{attachInfo}, + }, + } + + programs = append(programs, xdpProgram) + + // programMap[bpfFentryFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + // Type: bpfmaniov1alpha1.ProgTypeFentry, + // Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ + // BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + // BpfFunctionName: bpfFentryFunctionName, + // }, + // FentryLoadInfo: bpfmaniov1alpha1.FentryLoadInfo{FunctionName: functionFentryName}, + // Attach: true, + // }, + // } + + // programMap[bpfKprobeFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + // Type: bpfmaniov1alpha1.ProgTypeKprobe, + // Kprobe: &bpfmaniov1alpha1.KprobeProgramInfo{ + // BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + // BpfFunctionName: bpfKprobeFunctionName, + // }, + // AttachPoints: []bpfmaniov1alpha1.KprobeAttachInfo{ + // { + // FunctionName: functionKprobeName, + // Offset: uint64(offset), + // RetProbe: retprobe, + // }, + // }, + // }, + // } + + // programMap[bpfTracepointFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + // Type: bpfmaniov1alpha1.ProgTypeTracepoint, + // Tracepoint: &bpfmaniov1alpha1.TracepointProgramInfo{ + // BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + // BpfFunctionName: bpfTracepointFunctionName, + // }, + // AttachPoints: []bpfmaniov1alpha1.TracepointAttachInfo{ + // { + // Name: tracepointName, + // }, + // }, + // }, + // } + + app := &bpfmaniov1alpha1.BpfApplication{ + ObjectMeta: metav1.ObjectMeta{ + Name: bpfAppName, + }, + Spec: bpfmaniov1alpha1.BpfApplicationSpec{ + BpfAppCommon: bpfmaniov1alpha1.BpfAppCommon{ + NodeSelector: metav1.LabelSelector{}, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + Programs: programs, + }, + } + + // The expected accompanying BpfProgram object + expectedBpfAppState := &bpfmaniov1alpha1.BpfApplicationState{ + ObjectMeta: metav1.ObjectMeta{ + Name: bpfAppStateName, + OwnerReferences: []metav1.OwnerReference{ + { + Name: app.Name, + Controller: &[]bool{true}[0], + }, + }, + Labels: map[string]string{internal.BpfProgramOwner: app.Name, internal.K8sHostLabel: fakeNode.Name}, + Finalizers: []string{internal.BpfApplicationControllerFinalizer}, + }, + Spec: bpfmaniov1alpha1.BpfApplicationStateSpec{ + AppLoadStatus: bpfmaniov1alpha1.BpfProgCondLoaded, + Programs: []bpfmaniov1alpha1.BpfApplicationProgramState{}, + }, + Status: bpfmaniov1alpha1.BpfAppStatus{ + Conditions: []metav1.Condition{bpfmaniov1alpha1.ProgramReconcileSuccess.Condition("")}, + }, + } + + // Objects to track in the fake client. + objs := []runtime.Object{fakeNode, app, expectedBpfAppState} + + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, app) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfApplicationState{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfApplicationStateList{}) + + // Create a fake client to mock API calls. + cl := fake.NewClientBuilder().WithStatusSubresource(app).WithRuntimeObjects(objs...).Build() + + rc := ReconcilerCommon[bpfmaniov1alpha1.BpfApplicationState, bpfmaniov1alpha1.BpfApplicationStateList]{ + Client: cl, + Scheme: s, + } + + cpr := ClusterProgramReconciler{ + ReconcilerCommon: rc, + } + + // Set development Logger so we can see all logs in tests. + logf.SetLogger(zap.New(zap.UseFlagOptions(&zap.Options{Development: true}))) + + // Create a ApplicationProgram object with the scheme and fake client. + r := &BpfApplicationReconciler{ClusterProgramReconciler: cpr} + + // Mock request to simulate Reconcile() being called on an event for a + // watched resource . + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: bpfAppName, + }, + } + + // First reconcile should add the finalizer to the applicationProgram object + res, err := r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Require no requeue + require.False(t, res.Requeue) + + // Check the BpfProgram Object was created successfully + err = cl.Get(ctx, types.NamespacedName{Name: app.Name, Namespace: metav1.NamespaceAll}, app) + require.NoError(t, err) + + // Check the bpfman-operator finalizer was successfully added + require.Contains(t, app.GetFinalizers(), internal.BpfmanOperatorFinalizer) + + // NOTE: THIS IS A TEST FOR AN ERROR PATH. THERE SHOULD NEVER BE MORE THAN + // ONE CONDITION. + if multiCondition { + // Add some random conditions and verify that the condition still gets + // updated correctly. + meta.SetStatusCondition(&app.Status.Conditions, bpfmaniov1alpha1.ProgramDeleteError.Condition("bogus condition #1")) + if err := r.Status().Update(ctx, app); err != nil { + r.Logger.V(1).Info("failed to set App Program object status") + } + meta.SetStatusCondition(&app.Status.Conditions, bpfmaniov1alpha1.ProgramReconcileError.Condition("bogus condition #2")) + if err := r.Status().Update(ctx, app); err != nil { + r.Logger.V(1).Info("failed to set App Program object status") + } + // Make sure we have 2 conditions + require.Equal(t, 2, len(app.Status.Conditions)) + } + + // Second reconcile should check bpfProgram Status and write Success condition to tcProgram Status + res, err = r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Require no requeue + require.False(t, res.Requeue) + + // Check the BpfProgram Object was created successfully + err = cl.Get(ctx, types.NamespacedName{Name: app.Name, Namespace: metav1.NamespaceAll}, app) + require.NoError(t, err) + + // Make sure we only have 1 condition now + require.Equal(t, 1, len(app.Status.Conditions)) + // Make sure it's the right one. + require.Equal(t, app.Status.Conditions[0].Type, string(bpfmaniov1alpha1.ProgramReconcileSuccess)) +} + +func TestAppProgramReconcile(t *testing.T) { + appProgramReconcile(t, false) +} + +func TestAppUpdateStatus(t *testing.T) { + appProgramReconcile(t, true) +} diff --git a/controllers/app-operator/application-cl-programs.go b/controllers/app-operator/application-cl-programs.go new file mode 100644 index 000000000..831c550eb --- /dev/null +++ b/controllers/app-operator/application-cl-programs.go @@ -0,0 +1,123 @@ +/* +Copyright 2024 The bpfman Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package appoperator + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + internal "github.com/bpfman/bpfman-operator/internal" +) + +//+kubebuilder:rbac:groups=bpfman.io,resources=bpfapplications,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=bpfman.io,resources=bpfapplications/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=bpfman.io,resources=bpfapplications/finalizers,verbs=update + +// BpfApplicationReconciler reconciles a BpfApplication object +type BpfApplicationReconciler struct { + ClusterProgramReconciler +} + +//lint:ignore U1000 Linter claims function unused, but generics confusing linter +func (r *BpfApplicationReconciler) getRecCommon() *ReconcilerCommon[bpfmaniov1alpha1.BpfApplicationState, bpfmaniov1alpha1.BpfApplicationStateList] { + return &r.ClusterProgramReconciler.ReconcilerCommon +} + +//lint:ignore U1000 Linter claims function unused, but generics confusing linter +func (r *BpfApplicationReconciler) getFinalizer() string { + return internal.BpfApplicationControllerFinalizer +} + +// SetupWithManager sets up the controller with the Manager. +func (r *BpfApplicationReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&bpfmaniov1alpha1.BpfApplication{}). + WithOptions(controller.Options{MaxConcurrentReconciles: 1}). + // Watch bpfPrograms which are owned by BpfApplications + Watches( + &bpfmaniov1alpha1.BpfApplicationState{}, + &handler.EnqueueRequestForObject{}, + builder.WithPredicates(statusChangedPredicateCluster()), + ). + Complete(r) +} + +func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + r.Logger = ctrl.Log.WithName("application") + r.Logger.Info("BpfApplication Reconcile enter", "Name", req.NamespacedName.Name) + + appProgram := &bpfmaniov1alpha1.BpfApplication{} + if err := r.Get(ctx, req.NamespacedName, appProgram); err != nil { + // Reconcile was triggered by bpfProgram event, get parent appProgram Object. + if errors.IsNotFound(err) { + bpfAppState := &bpfmaniov1alpha1.BpfApplicationState{} + if err := r.Get(ctx, req.NamespacedName, bpfAppState); err != nil { + if errors.IsNotFound(err) { + r.Logger.V(1).Info("bpfProgram not found stale reconcile, exiting", "Name", req.NamespacedName) + } else { + r.Logger.Error(err, "failed getting bpfProgram Object", "Name", req.NamespacedName) + } + return ctrl.Result{}, nil + } + + // Get owning appProgram object from ownerRef + ownerRef := metav1.GetControllerOf(bpfAppState) + if ownerRef == nil { + return ctrl.Result{Requeue: false}, fmt.Errorf("failed getting bpfProgram Object owner") + } + + if err := r.Get(ctx, types.NamespacedName{Namespace: corev1.NamespaceAll, Name: ownerRef.Name}, appProgram); err != nil { + if errors.IsNotFound(err) { + r.Logger.Info("Application Programs from ownerRef not found stale reconcile exiting", "Name", req.NamespacedName) + } else { + r.Logger.Error(err, "failed getting Application Programs Object from ownerRef", "Name", req.NamespacedName) + } + return ctrl.Result{}, nil + } + + } else { + r.Logger.Error(err, "failed getting Application Programs Object", "Name", req.NamespacedName) + return ctrl.Result{}, nil + } + } + + return reconcileBpfProgram(ctx, r, appProgram) +} + +//lint:ignore U1000 Linter claims function unused, but generics confusing linter +func (r *BpfApplicationReconciler) updateStatus(ctx context.Context, _namespace string, name string, cond bpfmaniov1alpha1.ProgramConditionType, message string) (ctrl.Result, error) { + // Sometimes we end up with a stale FentryProgram due to races, do this + // get to ensure we're up to date before attempting a status update. + app := &bpfmaniov1alpha1.BpfApplication{} + if err := r.Get(ctx, types.NamespacedName{Namespace: corev1.NamespaceAll, Name: name}, app); err != nil { + r.Logger.V(1).Info("failed to get fresh Application Programs object...requeuing") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + + return r.updateCondition(ctx, app, &app.Status.Conditions, cond, message) +} diff --git a/controllers/app-operator/common.go b/controllers/app-operator/common.go new file mode 100644 index 000000000..ef3b5981c --- /dev/null +++ b/controllers/app-operator/common.go @@ -0,0 +1,244 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package appoperator + +import ( + "context" + "fmt" + "time" + + corev1 "k8s.io/api/core/v1" + meta "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + internal "github.com/bpfman/bpfman-operator/internal" + bpfmanHelpers "github.com/bpfman/bpfman-operator/pkg/helpers" + "github.com/go-logr/logr" +) + +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationstates,verbs=get;list;watch +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfnsprograms,verbs=get;list;watch +// +kubebuilder:rbac:groups=bpfman.io,namespace=bpfman,resources=bpfnsprograms,verbs=get;list;watch +// +kubebuilder:rbac:groups=core,resources=nodes,verbs=get;list;watch + +const ( + retryDurationOperator = 5 * time.Second +) + +type BpfProgOper interface { + GetName() string + + GetLabels() map[string]string + GetStatus() *bpfmaniov1alpha1.BpfAppStatus +} + +type BpfProgListOper[T any] interface { + // bpfmniov1alpha1.BpfProgramList | bpfmaniov1alpha1.BpfNsProgramList + + GetItems() []T +} + +// ReconcilerCommon reconciles a BpfProgram object +type ReconcilerCommon[T BpfProgOper, TL BpfProgListOper[T]] struct { + client.Client + Scheme *runtime.Scheme + Logger logr.Logger +} + +// bpfmanReconciler defines a k8s reconciler which can program bpfman. +type ProgramReconciler[T BpfProgOper, TL BpfProgListOper[T]] interface { + // BPF Cluster of Namespaced Reconciler + getBpfList(ctx context.Context, + progName string, + progNamespace string, + ) (*TL, error) + containsFinalizer(bpfProgram *T, finalizer string) bool + + // *Program Reconciler + getRecCommon() *ReconcilerCommon[T, TL] + updateStatus(ctx context.Context, + namespace string, + name string, + cond bpfmaniov1alpha1.ProgramConditionType, + message string) (ctrl.Result, error) + getFinalizer() string +} + +func reconcileBpfProgram[T BpfProgOper, TL BpfProgListOper[T]]( + ctx context.Context, + rec ProgramReconciler[T, TL], + app client.Object, +) (ctrl.Result, error) { + r := rec.getRecCommon() + progName := app.GetName() + progNamespace := app.GetNamespace() + + r.Logger.V(1).Info("Reconciling Program", "Namespace", progNamespace, "Name", progName) + + if !controllerutil.ContainsFinalizer(app, internal.BpfmanOperatorFinalizer) { + r.Logger.V(1).Info("Add Finalizer", "Namespace", progNamespace, "ProgramName", progName) + return r.addFinalizer(ctx, app, internal.BpfmanOperatorFinalizer) + } + + // reconcile Program Object on all other events + // list all existing bpfProgram state for the given Program + bpfAppStateObjs, err := rec.getBpfList(ctx, progName, progNamespace) + if err != nil { + r.Logger.Error(err, "failed to get freshPrograms for full reconcile") + return ctrl.Result{}, nil + } + + // List all nodes since a bpfprogram object will always be created for each + nodes := &corev1.NodeList{} + if err := r.List(ctx, nodes, &client.ListOptions{}); err != nil { + r.Logger.Error(err, "failed getting nodes for full reconcile") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + + // If the program isn't being deleted, make sure that each node has at + // least one bpfprogram object. If not, Return NotYetLoaded Status. + if app.GetDeletionTimestamp().IsZero() { + for _, node := range nodes.Items { + nodeFound := false + for _, program := range (*bpfAppStateObjs).GetItems() { + bpfProgramState := program.GetLabels()[internal.K8sHostLabel] + if node.Name == bpfProgramState { + nodeFound = true + break + } + } + if !nodeFound { + return rec.updateStatus(ctx, progNamespace, progName, bpfmaniov1alpha1.ProgramNotYetLoaded, "") + } + } + } + + failedBpfPrograms := []string{} + finalApplied := []string{} + // Make sure no bpfPrograms had any issues in the loading or unloading process + for _, bpfAppState := range (*bpfAppStateObjs).GetItems() { + + if rec.containsFinalizer(&bpfAppState, rec.getFinalizer()) { + finalApplied = append(finalApplied, bpfAppState.GetName()) + } + + status := bpfAppState.GetStatus() + if bpfmanHelpers.IsBpfAppStateConditionFailure(&status.Conditions) { + failedBpfPrograms = append(failedBpfPrograms, bpfAppState.GetName()) + } + } + + if !app.GetDeletionTimestamp().IsZero() { + // Only remove bpfman-operator finalizer if all bpfProgram Objects are ready to be pruned (i.e there are no + // bpfPrograms with a finalizer) + if len(finalApplied) == 0 { + // Causes Requeue + return r.removeFinalizer(ctx, app, internal.BpfmanOperatorFinalizer) + } + + // Causes Requeue + return rec.updateStatus(ctx, progNamespace, progName, bpfmaniov1alpha1.ProgramDeleteError, + fmt.Sprintf("Program Deletion failed on the following bpfProgram Objects: %v", finalApplied)) + } + + if len(failedBpfPrograms) != 0 { + // Causes Requeue + return rec.updateStatus(ctx, progNamespace, progName, bpfmaniov1alpha1.ProgramReconcileError, + fmt.Sprintf("bpfProgramReconciliation failed on the following bpfProgram Objects: %v", failedBpfPrograms)) + } + + // Causes Requeue + return rec.updateStatus(ctx, progNamespace, progName, bpfmaniov1alpha1.ProgramReconcileSuccess, "") +} + +func (r *ReconcilerCommon[T, TL]) removeFinalizer(ctx context.Context, app client.Object, finalizer string) (ctrl.Result, error) { + r.Logger.Info("Calling KubeAPI to delete Program Finalizer", "Type", app.GetObjectKind().GroupVersionKind().Kind, "Name", app.GetName()) + + if changed := controllerutil.RemoveFinalizer(app, finalizer); changed { + err := r.Update(ctx, app) + if err != nil { + r.Logger.Error(err, "failed to remove bpfProgram Finalizer") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + } + + return ctrl.Result{}, nil +} + +func (r *ReconcilerCommon[T, TL]) addFinalizer(ctx context.Context, app client.Object, finalizer string) (ctrl.Result, error) { + controllerutil.AddFinalizer(app, finalizer) + + r.Logger.Info("Calling KubeAPI to add Program Finalizer", "Type", app.GetObjectKind().GroupVersionKind().Kind, "Name", app.GetName()) + err := r.Update(ctx, app) + if err != nil { + r.Logger.V(1).Info("failed adding bpfman-operator finalizer to Program...requeuing") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + + return ctrl.Result{}, nil +} + +func (r *ReconcilerCommon[T, TL]) updateCondition( + ctx context.Context, + obj client.Object, + conditions *[]metav1.Condition, + cond bpfmaniov1alpha1.ProgramConditionType, + message string, +) (ctrl.Result, error) { + + r.Logger.V(1).Info("updateCondition()", "existing conds", conditions, "new cond", cond) + + if conditions != nil { + numConditions := len(*conditions) + + if numConditions == 1 { + if (*conditions)[0].Type == string(cond) { + r.Logger.Info("No change in status", "existing condition", (*conditions)[0].Type) + // No change, so just return false -- not updated + return ctrl.Result{}, nil + } else { + // We're changing the condition, so delete this one. The + // new condition will be added below. + *conditions = nil + } + } else if numConditions > 1 { + // We should only ever have one condition, so we shouldn't hit this + // case. However, if we do, log a message, delete the existing + // conditions, and add the new one below. + r.Logger.Info("more than one BpfProgramCondition", "numConditions", numConditions) + *conditions = nil + } + // if numConditions == 0, just add the new condition below. + } + + meta.SetStatusCondition(conditions, cond.Condition(message)) + + r.Logger.Info("Calling KubeAPI to update Program condition", "Type", obj.GetObjectKind().GroupVersionKind().Kind, + "Name", obj.GetName(), "condition", cond.Condition(message).Type) + if err := r.Status().Update(ctx, obj); err != nil { + r.Logger.V(1).Info("failed to set *Program object status...requeuing", "error", err) + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + + r.Logger.V(1).Info("condition updated", "new condition", cond) + return ctrl.Result{}, nil +} diff --git a/controllers/app-operator/common_cluster.go b/controllers/app-operator/common_cluster.go new file mode 100644 index 000000000..1ea5d9594 --- /dev/null +++ b/controllers/app-operator/common_cluster.go @@ -0,0 +1,83 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package appoperator + +import ( + "context" + "reflect" + + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + internal "github.com/bpfman/bpfman-operator/internal" +) + +type ClusterProgramReconciler struct { + ReconcilerCommon[bpfmaniov1alpha1.BpfApplicationState, bpfmaniov1alpha1.BpfApplicationStateList] +} + +//lint:ignore U1000 Linter claims function unused, but generics confusing linter +func (r *ClusterProgramReconciler) getBpfList( + ctx context.Context, + progName string, + _progNamespace string, +) (*bpfmaniov1alpha1.BpfApplicationStateList, error) { + + bpfProgramList := &bpfmaniov1alpha1.BpfApplicationStateList{} + + // Only list bpfPrograms for this Program + opts := []client.ListOption{ + client.MatchingLabels{internal.BpfProgramOwner: progName}, + } + + err := r.List(ctx, bpfProgramList, opts...) + if err != nil { + return nil, err + } + + return bpfProgramList, nil +} + +//lint:ignore U1000 Linter claims function unused, but generics confusing linter +func (r *ClusterProgramReconciler) containsFinalizer( + bpfProgram *bpfmaniov1alpha1.BpfApplicationState, + finalizer string, +) bool { + return controllerutil.ContainsFinalizer(bpfProgram, finalizer) +} + +func statusChangedPredicateCluster() predicate.Funcs { + return predicate.Funcs{ + GenericFunc: func(e event.GenericEvent) bool { + return false + }, + CreateFunc: func(e event.CreateEvent) bool { + return false + }, + UpdateFunc: func(e event.UpdateEvent) bool { + oldObject := e.ObjectOld.(*bpfmaniov1alpha1.BpfApplicationState) + newObject := e.ObjectNew.(*bpfmaniov1alpha1.BpfApplicationState) + return !reflect.DeepEqual(oldObject.GetStatus(), newObject.Status) + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return false + }, + } +} diff --git a/controllers/app-operator/configmap.go b/controllers/app-operator/configmap.go new file mode 100644 index 000000000..72f84327d --- /dev/null +++ b/controllers/app-operator/configmap.go @@ -0,0 +1,350 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package appoperator + +import ( + "context" + "io" + "os" + "reflect" + "strings" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + osv1 "github.com/openshift/api/security/v1" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + "github.com/bpfman/bpfman-operator/internal" +) + +// +kubebuilder:rbac:groups=apps,resources=daemonsets,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch;create +// +kubebuilder:rbac:groups=storage.k8s.io,resources=csidrivers,verbs=get;list;watch;create;delete +// +kubebuilder:rbac:groups=security.openshift.io,resources=securitycontextconstraints,verbs=get;list;watch;create;delete +// +kubebuilder:rbac:groups=bpfman.io,resources=configmaps/finalizers,verbs=update + +type BpfmanConfigReconciler struct { + ClusterProgramReconciler + BpfmanStandardDeployment string + CsiDriverDeployment string + RestrictedSCC string + IsOpenshift bool +} + +// SetupWithManager sets up the controller with the Manager. +func (r *BpfmanConfigReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + // Watch the bpfman-daemon configmap to configure the bpfman deployment across the whole cluster + For(&corev1.ConfigMap{}, + builder.WithPredicates(bpfmanConfigPredicate())). + // This only watches the bpfman daemonset which is stored on disk and will be created + // by this operator. We're doing a manual watch since the operator (As a controller) + // doesn't really want to have an owner-ref since we don't have a CRD for + // configuring it, only a configmap. + Owns( + &appsv1.DaemonSet{}, + builder.WithPredicates(bpfmanDaemonPredicate())). + Complete(r) +} + +func (r *BpfmanConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + r.Logger = ctrl.Log.WithName("configMap") + + bpfmanConfig := &corev1.ConfigMap{} + if err := r.Get(ctx, req.NamespacedName, bpfmanConfig); err != nil { + if !errors.IsNotFound(err) { + r.Logger.Error(err, "failed getting bpfman config", "ReconcileObject", req.NamespacedName) + return ctrl.Result{}, nil + } + } else { + if updated := controllerutil.AddFinalizer(bpfmanConfig, internal.BpfmanOperatorFinalizer); updated { + if err := r.Update(ctx, bpfmanConfig); err != nil { + r.Logger.Error(err, "failed adding bpfman-operator finalizer to bpfman config") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + } else { + return r.ReconcileBpfmanConfig(ctx, req, bpfmanConfig) + } + } + + return ctrl.Result{}, nil +} + +func (r *BpfmanConfigReconciler) ReconcileBpfmanConfig(ctx context.Context, req ctrl.Request, bpfmanConfig *corev1.ConfigMap) (ctrl.Result, error) { + bpfmanCsiDriver := &storagev1.CSIDriver{} + // one-shot try to create bpfman's CSIDriver object if it doesn't exist, does not re-trigger reconcile. + if err := r.Get(ctx, types.NamespacedName{Namespace: corev1.NamespaceAll, Name: internal.BpfmanCsiDriverName}, bpfmanCsiDriver); err != nil { + if errors.IsNotFound(err) { + bpfmanCsiDriver = LoadCsiDriver(r.CsiDriverDeployment) + + r.Logger.Info("Creating Bpfman csi driver object") + if err := r.Create(ctx, bpfmanCsiDriver); err != nil { + r.Logger.Error(err, "Failed to create Bpfman csi driver") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + } else { + r.Logger.Error(err, "Failed to get csi.bpfman.io csidriver") + } + } + + if r.IsOpenshift { + bpfmanRestrictedSCC := &osv1.SecurityContextConstraints{} + // one-shot try to create the bpfman-restricted SCC if it doesn't exist, does not re-trigger reconcile. + if err := r.Get(ctx, types.NamespacedName{Namespace: corev1.NamespaceAll, Name: internal.BpfmanRestrictedSccName}, bpfmanRestrictedSCC); err != nil { + if errors.IsNotFound(err) { + bpfmanRestrictedSCC = LoadRestrictedSecurityContext(r.RestrictedSCC) + + r.Logger.Info("Creating Bpfman restricted scc object for unprivileged users to bind to") + if err := r.Create(ctx, bpfmanRestrictedSCC); err != nil { + r.Logger.Error(err, "Failed to create Bpfman restricted scc") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + } else { + r.Logger.Error(err, "Failed to get bpfman-restricted scc") + } + } + } + + bpfmanDeployment := &appsv1.DaemonSet{} + staticBpfmanDeployment := LoadAndConfigureBpfmanDs(bpfmanConfig, r.BpfmanStandardDeployment) + r.Logger.V(1).Info("StaticBpfmanDeployment with CSI", "DS", staticBpfmanDeployment) + if err := r.Get(ctx, types.NamespacedName{Namespace: bpfmanConfig.Namespace, Name: internal.BpfmanDsName}, bpfmanDeployment); err != nil { + if errors.IsNotFound(err) { + r.Logger.Info("Creating Bpfman Daemon") + // Causes Requeue + if err := r.Create(ctx, staticBpfmanDeployment); err != nil { + r.Logger.Error(err, "Failed to create Bpfman Daemon") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + return ctrl.Result{}, nil + } + + r.Logger.Error(err, "Failed to get bpfman daemon") + return ctrl.Result{}, nil + } + + if !bpfmanConfig.DeletionTimestamp.IsZero() { + r.Logger.Info("Deleting bpfman daemon and config") + controllerutil.RemoveFinalizer(bpfmanDeployment, internal.BpfmanOperatorFinalizer) + + err := r.Update(ctx, bpfmanDeployment) + if err != nil { + r.Logger.Error(err, "failed removing bpfman-operator finalizer from bpfmanDs") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + + bpfmanCsiDriver := &storagev1.CSIDriver{} + + // one-shot try to delete bpfman's CSIDriver object only if it exists. + if err := r.Get(ctx, types.NamespacedName{Namespace: corev1.NamespaceAll, Name: internal.BpfmanCsiDriverName}, bpfmanCsiDriver); err == nil { + r.Logger.Info("Deleting Bpfman csi driver object") + if err := r.Delete(ctx, bpfmanCsiDriver); err != nil { + r.Logger.Error(err, "Failed to delete Bpfman csi driver") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + } + + if err = r.Delete(ctx, bpfmanDeployment); err != nil { + r.Logger.Error(err, "failed deleting bpfman DS") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + + if r.IsOpenshift { + bpfmanRestrictedSCC := &osv1.SecurityContextConstraints{} + // one-shot try to delete the bpfman + // restricted SCC object but only if it + // exists. + if err := r.Get(ctx, types.NamespacedName{Namespace: corev1.NamespaceAll, Name: internal.BpfmanRestrictedSccName}, bpfmanRestrictedSCC); err == nil { + r.Logger.Info("Deleting Bpfman restricted SCC object") + if err := r.Delete(ctx, bpfmanRestrictedSCC); err != nil { + r.Logger.Error(err, "Failed to delete Bpfman restricted SCC") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + } + } + + controllerutil.RemoveFinalizer(bpfmanConfig, internal.BpfmanOperatorFinalizer) + err = r.Update(ctx, bpfmanConfig) + if err != nil { + r.Logger.Error(err, "failed removing bpfman-operator finalizer from bpfman config") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + + return ctrl.Result{}, nil + } + + if !reflect.DeepEqual(staticBpfmanDeployment.Spec, bpfmanDeployment.Spec) { + r.Logger.Info("Reconciling bpfman") + + // Causes Requeue + if err := r.Update(ctx, staticBpfmanDeployment); err != nil { + r.Logger.Error(err, "failed reconciling bpfman deployment") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + } + + return ctrl.Result{}, nil +} + +// Only reconcile on bpfman-daemon Daemonset events. +func bpfmanDaemonPredicate() predicate.Funcs { + return predicate.Funcs{ + GenericFunc: func(e event.GenericEvent) bool { + return e.Object.GetName() == internal.BpfmanDsName + }, + CreateFunc: func(e event.CreateEvent) bool { + return e.Object.GetName() == internal.BpfmanDsName + }, + UpdateFunc: func(e event.UpdateEvent) bool { + return e.ObjectNew.GetName() == internal.BpfmanDsName + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return e.Object.GetName() == internal.BpfmanDsName + }, + } +} + +// Only reconcile on bpfman-config configmap events. +func bpfmanConfigPredicate() predicate.Funcs { + return predicate.Funcs{ + GenericFunc: func(e event.GenericEvent) bool { + return e.Object.GetName() == internal.BpfmanConfigName + }, + CreateFunc: func(e event.CreateEvent) bool { + return e.Object.GetName() == internal.BpfmanConfigName + }, + UpdateFunc: func(e event.UpdateEvent) bool { + return e.ObjectNew.GetName() == internal.BpfmanConfigName + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return e.Object.GetName() == internal.BpfmanConfigName + }, + } +} + +// LoadRestrictedSecurityContext loads the bpfman-restricted SCC from disk which +// users can bind to in order to utilize bpfman in an unprivileged way. +func LoadRestrictedSecurityContext(path string) *osv1.SecurityContextConstraints { + // Load static SCC yaml from disk + file, err := os.Open(path) + if err != nil { + panic(err) + } + + b, err := io.ReadAll(file) + if err != nil { + panic(err) + } + + bpfmanRestrictedSCC := &osv1.SecurityContextConstraints{} + decode := scheme.Codecs.UniversalDeserializer().Decode + obj, _, _ := decode(b, nil, bpfmanRestrictedSCC) + + return obj.(*osv1.SecurityContextConstraints) +} + +func LoadCsiDriver(path string) *storagev1.CSIDriver { + // Load static CSIDriver yaml from disk + file, err := os.Open(path) + if err != nil { + panic(err) + } + + b, err := io.ReadAll(file) + if err != nil { + panic(err) + } + + decode := scheme.Codecs.UniversalDeserializer().Decode + obj, _, _ := decode(b, nil, nil) + + return obj.(*storagev1.CSIDriver) +} + +func LoadAndConfigureBpfmanDs(config *corev1.ConfigMap, path string) *appsv1.DaemonSet { + // Load static bpfman deployment from disk + file, err := os.Open(path) + if err != nil { + panic(err) + } + + b, err := io.ReadAll(file) + if err != nil { + panic(err) + } + + decode := scheme.Codecs.UniversalDeserializer().Decode + obj, _, _ := decode(b, nil, nil) + + staticBpfmanDeployment := obj.(*appsv1.DaemonSet) + + // Runtime Configurable fields + bpfmanImage := config.Data["bpfman.image"] + bpfmanAgentImage := config.Data["bpfman.agent.image"] + bpfmanLogLevel := config.Data["bpfman.log.level"] + bpfmanAgentLogLevel := config.Data["bpfman.agent.log.level"] + bpfmanHealthProbeAddr := config.Data["bpfman.agent.healthprobe.addr"] + bpfmanMetricAddr := config.Data["bpfman.agent.metric.addr"] + + // Annotate the log level on the ds so we get automatic restarts on changes. + if staticBpfmanDeployment.Spec.Template.ObjectMeta.Annotations == nil { + staticBpfmanDeployment.Spec.Template.ObjectMeta.Annotations = make(map[string]string) + } + + staticBpfmanDeployment.Spec.Template.ObjectMeta.Annotations["bpfman.io.bpfman.loglevel"] = bpfmanLogLevel + staticBpfmanDeployment.Spec.Template.ObjectMeta.Annotations["bpfman.io.bpfman.agent.loglevel"] = bpfmanAgentLogLevel + staticBpfmanDeployment.Spec.Template.ObjectMeta.Annotations["bpfman.io.bpfman.agent.healthprobeaddr"] = bpfmanHealthProbeAddr + staticBpfmanDeployment.Spec.Template.ObjectMeta.Annotations["bpfman.io.bpfman.agent.metricaddr"] = bpfmanMetricAddr + staticBpfmanDeployment.Name = internal.BpfmanDsName + staticBpfmanDeployment.Namespace = config.Namespace + staticBpfmanDeployment.Spec.Template.Spec.AutomountServiceAccountToken = ptr.To(true) + for cindex, container := range staticBpfmanDeployment.Spec.Template.Spec.Containers { + if container.Name == internal.BpfmanContainerName { + staticBpfmanDeployment.Spec.Template.Spec.Containers[cindex].Image = bpfmanImage + } else if container.Name == internal.BpfmanAgentContainerName { + staticBpfmanDeployment.Spec.Template.Spec.Containers[cindex].Image = bpfmanAgentImage + + for aindex, arg := range container.Args { + if bpfmanHealthProbeAddr != "" { + if strings.Contains(arg, "health-probe-bind-address") { + staticBpfmanDeployment.Spec.Template.Spec.Containers[cindex].Args[aindex] = + "--health-probe-bind-address=" + bpfmanHealthProbeAddr + } + } + if bpfmanMetricAddr != "" { + if strings.Contains(arg, "metrics-bind-address") { + staticBpfmanDeployment.Spec.Template.Spec.Containers[cindex].Args[aindex] = + "--metrics-bind-address=" + bpfmanMetricAddr + } + } + } + } + } + controllerutil.AddFinalizer(staticBpfmanDeployment, internal.BpfmanOperatorFinalizer) + + return staticBpfmanDeployment +} diff --git a/controllers/app-operator/configmap_test.go b/controllers/app-operator/configmap_test.go new file mode 100644 index 000000000..dd76992ab --- /dev/null +++ b/controllers/app-operator/configmap_test.go @@ -0,0 +1,256 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package appoperator + +import ( + "context" + "fmt" + "os" + "path/filepath" + "reflect" + "testing" + + osv1 "github.com/openshift/api/security/v1" + "github.com/stretchr/testify/require" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + "github.com/bpfman/bpfman-operator/internal" +) + +// setupTestEnvironment sets up the testing environment for the +// BpfmanConfigReconciler. It initialises a fake client with a +// ConfigMap, registers necessary types with the runtime scheme, and +// configures the reconciler with the fake client and scheme. The +// function will set the RestrictedSCC field on the reconciler object +// if the isOpenShift parameter is set to true, which is required for +// OpenShift-specific tests. +// +// Parameters: +// - isOpenShift (bool): +// A flag indicating whether to set up the test environment for +// OpenShift, which includes setting the RestrictedSCC field on the +// reconciler object. +// +// Returns: +// - *BpfmanConfigReconciler: The configured reconciler. +// - *corev1.ConfigMap: The test ConfigMap object. +// - reconcile.Request: The reconcile request object. +// - context.Context: The context for the reconcile functio +func setupTestEnvironment(isOpenShift bool) (*BpfmanConfigReconciler, *corev1.ConfigMap, reconcile.Request, context.Context, client.Client) { + // A configMap for bpfman with metadata and spec. + bpfmanConfig := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: internal.BpfmanConfigName, + Namespace: internal.BpfmanNs, + }, + Data: map[string]string{ + "bpfman.agent.image": "BPFMAN_AGENT_IS_SCARY", + "bpfman.image": "FAKE-IMAGE", + "bpfman.agent.log.level": "FAKE", + }, + } + + // Objects to track in the fake client. + objs := []runtime.Object{bpfmanConfig} + + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(corev1.SchemeGroupVersion, &corev1.ConfigMap{}) + s.AddKnownTypes(appsv1.SchemeGroupVersion, &appsv1.DaemonSet{}) + s.AddKnownTypes(storagev1.SchemeGroupVersion, &storagev1.CSIDriver{}) + s.AddKnownTypes(osv1.GroupVersion, &osv1.SecurityContextConstraints{}) + + // Create a fake client to mock API calls. + cl := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build() + + // Set development Logger so we can see all logs in tests. + logf.SetLogger(zap.New(zap.UseFlagOptions(&zap.Options{Development: true}))) + + rc := ReconcilerCommon[bpfmaniov1alpha1.BpfApplicationState, bpfmaniov1alpha1.BpfApplicationStateList]{ + Client: cl, + Scheme: s, + } + + cpr := ClusterProgramReconciler{ + ReconcilerCommon: rc, + } + + // Create a BpfmanConfigReconciler object with the scheme and + // fake client. + r := &BpfmanConfigReconciler{ + ClusterProgramReconciler: cpr, + BpfmanStandardDeployment: resolveConfigPath(internal.BpfmanDaemonManifestPath), + CsiDriverDeployment: resolveConfigPath(internal.BpfmanCsiDriverPath), + IsOpenshift: isOpenShift, + } + if isOpenShift { + r.RestrictedSCC = resolveConfigPath(internal.BpfmanRestrictedSCCPath) + } + + // Mock request object to simulate Reconcile() being called on + // an event for a watched resource. + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: internal.BpfmanConfigName, + Namespace: internal.BpfmanNs, + }, + } + + return r, bpfmanConfig, req, context.TODO(), cl +} + +// resolveConfigPath adjusts the path for configuration files so that +// lookup of path resolves from the perspective of the calling test. +func resolveConfigPath(path string) string { + testDir, _ := os.Getwd() + return filepath.Clean(filepath.Join(testDir, getRelativePathToRoot(testDir), path)) +} + +// getRelativePathToRoot calculates the relative path from the current +// directory to the project root. +func getRelativePathToRoot(currentDir string) string { + projectRoot := mustFindProjectRoot(currentDir, projectRootPredicate) + relPath, _ := filepath.Rel(currentDir, projectRoot) + return relPath +} + +// mustFindProjectRoot traverses up the directory tree to find the +// project root. The project root is identified by the provided +// closure. This function panics if, after walking the tree and +// reaching the root of the filesystem, the project root is not found. +func mustFindProjectRoot(currentDir string, isProjectRoot func(string) bool) string { + for { + if isProjectRoot(currentDir) { + return currentDir + } + if currentDir == filepath.Dir(currentDir) { + panic("project root not found") + } + // Move up to the parent directory. + currentDir = filepath.Dir(currentDir) + } +} + +// projectRootPredicate checks if the given directory is the project +// root by looking for the presence of a `go.mod` file and a `config` +// directory. Returns true if both are found, otherwise returns false. +func projectRootPredicate(dir string) bool { + if _, err := os.Stat(filepath.Join(dir, "go.mod")); os.IsNotExist(err) { + return false + } + if _, err := os.Stat(filepath.Join(dir, "config")); os.IsNotExist(err) { + return false + } + return true +} + +func TestBpfmanConfigReconcileAndDeleteNEW(t *testing.T) { + for _, tc := range []struct { + isOpenShift bool + }{ + {isOpenShift: false}, + {isOpenShift: true}, + } { + t.Run(fmt.Sprintf("isOpenShift: %v", tc.isOpenShift), func(t *testing.T) { + r, bpfmanConfig, req, ctx, cl := setupTestEnvironment(tc.isOpenShift) + require.Equal(t, tc.isOpenShift, r.RestrictedSCC != "", "RestrictedSCC should be non-empty for OpenShift and empty otherwise") + + // The expected bpfman daemonset + expectedBpfmanDs := LoadAndConfigureBpfmanDs(bpfmanConfig, resolveConfigPath(internal.BpfmanDaemonManifestPath)) + + // First reconcile will add bpfman-operator finalizer to bpfman configmap + res, err := r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Require no requeue + require.False(t, res.Requeue) + + // Check the BpfProgram Object was created successfully + err = cl.Get(ctx, types.NamespacedName{Name: internal.BpfmanConfigName, Namespace: internal.BpfmanNs}, bpfmanConfig) + require.NoError(t, err) + + // Check the bpfman-operator finalizer was successfully added + require.Contains(t, bpfmanConfig.GetFinalizers(), internal.BpfmanOperatorFinalizer) + + // Second reconcile will create bpfman daemonset and, when isOpenshift holds true, a SCC. + res, err = r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Require no requeue + require.False(t, res.Requeue) + + // Check the bpfman daemonset was created successfully + actualBpfmanDs := &appsv1.DaemonSet{} + + err = cl.Get(ctx, types.NamespacedName{Name: expectedBpfmanDs.Name, Namespace: expectedBpfmanDs.Namespace}, actualBpfmanDs) + require.NoError(t, err) + + // Check the bpfman daemonset was created with the correct configuration. + require.True(t, reflect.DeepEqual(actualBpfmanDs.Spec, expectedBpfmanDs.Spec)) + + if tc.isOpenShift { + // Check the SCC was created with the correct configuration. + actualRestrictedSCC := &osv1.SecurityContextConstraints{} + expectedRestrictedSCC := LoadRestrictedSecurityContext(resolveConfigPath(internal.BpfmanRestrictedSCCPath)) + err = cl.Get(ctx, types.NamespacedName{Name: internal.BpfmanRestrictedSccName, Namespace: corev1.NamespaceAll}, actualRestrictedSCC) + require.NoError(t, err) + // Match ResourceVersion's as that is the only expected difference (0 versus 1). + expectedRestrictedSCC.ResourceVersion = actualRestrictedSCC.ResourceVersion + require.True(t, reflect.DeepEqual(actualRestrictedSCC, expectedRestrictedSCC)) + } + + // Delete the bpfman configmap + err = cl.Delete(ctx, bpfmanConfig) + require.NoError(t, err) + + // Third reconcile will delete bpfman daemonset + res, err = r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Require no requeue + require.False(t, res.Requeue) + + err = cl.Get(ctx, types.NamespacedName{Name: expectedBpfmanDs.Name, Namespace: expectedBpfmanDs.Namespace}, actualBpfmanDs) + require.True(t, errors.IsNotFound(err)) + + err = cl.Get(ctx, types.NamespacedName{Name: bpfmanConfig.Name, Namespace: bpfmanConfig.Namespace}, bpfmanConfig) + require.True(t, errors.IsNotFound(err)) + + err = cl.Get(ctx, types.NamespacedName{Name: internal.BpfmanRestrictedSccName, Namespace: corev1.NamespaceAll}, &osv1.SecurityContextConstraints{}) + require.True(t, errors.IsNotFound(err)) + }) + } +} diff --git a/controllers/bpfman-agent/application-ns-program.go b/controllers/bpfman-agent/application-ns-program.go index 3d35dda33..709f5d4d4 100644 --- a/controllers/bpfman-agent/application-ns-program.go +++ b/controllers/bpfman-agent/application-ns-program.go @@ -95,7 +95,7 @@ func (r *BpfNsApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Req switch p.Type { case bpfmaniov1alpha1.ProgTypeUprobe, bpfmaniov1alpha1.ProgTypeUretprobe: - appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), sanitize(p.Uprobe.FunctionName), p.Uprobe.BpfFunctionName) + appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), sanitize(p.Uprobe.AttachPoints[0].FunctionName), p.Uprobe.BpfFunctionName) uprobeProgram := bpfmaniov1alpha1.UprobeNsProgram{ ObjectMeta: metav1.ObjectMeta{ Name: buildProgramName(a, p), @@ -119,13 +119,13 @@ func (r *BpfNsApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Req lastRec = rec case bpfmaniov1alpha1.ProgTypeTC: - _, ifErr := getInterfaces(&p.TC.InterfaceSelector, r.ourNode) + _, ifErr := getInterfaces(&p.TC.AttachPoints[0].InterfaceSelector, r.ourNode) if ifErr != nil { r.Logger.Error(ifErr, "failed to get interfaces for TC NS Program", "app program name", a.Name, "program index", j) continue } - appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), p.TC.Direction, p.TC.BpfFunctionName) + appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), p.TC.AttachPoints[0].Direction, p.TC.BpfFunctionName) tcProgram := bpfmaniov1alpha1.TcNsProgram{ ObjectMeta: metav1.ObjectMeta{ Name: buildProgramName(a, p), @@ -149,13 +149,13 @@ func (r *BpfNsApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Req lastRec = rec case bpfmaniov1alpha1.ProgTypeTCX: - _, ifErr := getInterfaces(&p.TCX.InterfaceSelector, r.ourNode) + _, ifErr := getInterfaces(&p.TCX.AttachPoints[0].InterfaceSelector, r.ourNode) if ifErr != nil { r.Logger.Error(ifErr, "failed to get interfaces for TCX Program", "app program name", a.Name, "program index", j) continue } - appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), p.TCX.Direction, p.TCX.BpfFunctionName) + appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), p.TCX.AttachPoints[0].Direction, p.TCX.BpfFunctionName) tcxProgram := bpfmaniov1alpha1.TcxNsProgram{ ObjectMeta: metav1.ObjectMeta{ Name: buildProgramName(a, p), @@ -179,7 +179,7 @@ func (r *BpfNsApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Req lastRec = rec case bpfmaniov1alpha1.ProgTypeXDP: - _, ifErr := getInterfaces(&p.XDP.InterfaceSelector, r.ourNode) + _, ifErr := getInterfaces(&p.XDP.AttachPoints[0].InterfaceSelector, r.ourNode) if ifErr != nil { r.Logger.Error(ifErr, "failed to get interfaces for XDP Program", "app program name", a.Name, "program index", j) @@ -267,7 +267,7 @@ func (r *BpfNsApplicationReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfNsProgram{}, builder.WithPredicates(predicate.And( internal.BpfNsProgramTypePredicate(internal.ApplicationString), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Only trigger reconciliation if node labels change since that could diff --git a/controllers/bpfman-agent/application-ns-program_test.go b/controllers/bpfman-agent/application-ns-program_test.go index ec441f90d..141c6df15 100644 --- a/controllers/bpfman-agent/application-ns-program_test.go +++ b/controllers/bpfman-agent/application-ns-program_test.go @@ -84,14 +84,18 @@ func TestBpfNsApplicationControllerCreate(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfUprobeFunctionName, }, - FunctionName: uprobeFunctionName, - Target: uprobeTarget, - Offset: uint64(uprobeOffset), - RetProbe: uprobeRetprobe, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "test", + AttachPoints: []bpfmaniov1alpha1.UprobeNsAttachInfo{ + { + FunctionName: uprobeFunctionName, + Target: uprobeTarget, + Offset: uint64(uprobeOffset), + RetProbe: uprobeRetprobe, + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "test", + }, + }, }, }, }, @@ -103,17 +107,21 @@ func TestBpfNsApplicationControllerCreate(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfXdpFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &fakeInts, - }, - Priority: 0, - ProceedOn: []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), - bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return"), - }, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "test", + AttachPoints: []bpfmaniov1alpha1.XdpNsAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &fakeInts, + }, + Priority: 0, + ProceedOn: []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), + bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return"), + }, + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "test", + }, + }, }, }, }, diff --git a/controllers/bpfman-agent/application-program.go b/controllers/bpfman-agent/application-program.go index 151e7680f..4d1d88484 100644 --- a/controllers/bpfman-agent/application-program.go +++ b/controllers/bpfman-agent/application-program.go @@ -140,7 +140,7 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque case bpfmaniov1alpha1.ProgTypeKprobe, bpfmaniov1alpha1.ProgTypeKretprobe: - appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), sanitize(p.Kprobe.FunctionName), p.Kprobe.BpfFunctionName) + appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), sanitize(p.Kprobe.AttachPoints[0].FunctionName), p.Kprobe.BpfFunctionName) kprobeProgram := bpfmaniov1alpha1.KprobeProgram{ ObjectMeta: metav1.ObjectMeta{ Name: buildProgramName(a, p), @@ -164,7 +164,7 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque case bpfmaniov1alpha1.ProgTypeUprobe, bpfmaniov1alpha1.ProgTypeUretprobe: - appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), sanitize(p.Uprobe.FunctionName), p.Uprobe.BpfFunctionName) + appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), sanitize(p.Uprobe.AttachPoints[0].FunctionName), p.Uprobe.BpfFunctionName) uprobeProgram := bpfmaniov1alpha1.UprobeProgram{ ObjectMeta: metav1.ObjectMeta{ Name: buildProgramName(a, p), @@ -210,13 +210,13 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque lastRec = rec case bpfmaniov1alpha1.ProgTypeTC: - _, ifErr := getInterfaces(&p.TC.InterfaceSelector, r.ourNode) + _, ifErr := getInterfaces(&p.TC.AttachPoints[0].InterfaceSelector, r.ourNode) if ifErr != nil { r.Logger.Error(ifErr, "failed to get interfaces for TC Program", "app program name", a.Name, "program index", j) continue } - appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), p.TC.Direction, p.TC.BpfFunctionName) + appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), p.TC.AttachPoints[0].Direction, p.TC.BpfFunctionName) tcProgram := bpfmaniov1alpha1.TcProgram{ ObjectMeta: metav1.ObjectMeta{ Name: buildProgramName(a, p), @@ -239,13 +239,13 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque lastRec = rec case bpfmaniov1alpha1.ProgTypeTCX: - _, ifErr := getInterfaces(&p.TCX.InterfaceSelector, r.ourNode) + _, ifErr := getInterfaces(&p.TCX.AttachPoints[0].InterfaceSelector, r.ourNode) if ifErr != nil { r.Logger.Error(ifErr, "failed to get interfaces for TCX Program", "app program name", a.Name, "program index", j) continue } - appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), p.TCX.Direction, p.TCX.BpfFunctionName) + appProgramId := fmt.Sprintf("%s-%s-%s", strings.ToLower(string(p.Type)), p.TCX.AttachPoints[0].Direction, p.TCX.BpfFunctionName) tcxProgram := bpfmaniov1alpha1.TcxProgram{ ObjectMeta: metav1.ObjectMeta{ Name: buildProgramName(a, p), @@ -268,7 +268,7 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque lastRec = rec case bpfmaniov1alpha1.ProgTypeXDP: - _, ifErr := getInterfaces(&p.XDP.InterfaceSelector, r.ourNode) + _, ifErr := getInterfaces(&p.XDP.AttachPoints[0].InterfaceSelector, r.ourNode) if ifErr != nil { r.Logger.Error(ifErr, "failed to get interfaces for XDP Program", "app program name", a.Name, "program index", j) @@ -355,7 +355,7 @@ func (r *BpfApplicationReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfProgram{}, builder.WithPredicates(predicate.And( internal.BpfProgramTypePredicate(internal.ApplicationString), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Only trigger reconciliation if node labels change since that could diff --git a/controllers/bpfman-agent/application-program_test.go b/controllers/bpfman-agent/application-program_test.go index 067f4c581..41a50d9de 100644 --- a/controllers/bpfman-agent/application-program_test.go +++ b/controllers/bpfman-agent/application-program_test.go @@ -51,7 +51,39 @@ func TestBpfApplicationControllerCreate(t *testing.T) { kprobecontainerpid int32 = 0 ) - // A AppProgram object with metadata and spec. + programs := []bpfmaniov1alpha1.BpfApplicationProgram{} + + fentryProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + Type: bpfmaniov1alpha1.ProgTypeFentry, + Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfFentryFunctionName, + }, + FentryLoadInfo: bpfmaniov1alpha1.FentryLoadInfo{FunctionName: fentryFunctionName}, + FentryAttachInfo: bpfmaniov1alpha1.FentryAttachInfo{Attach: true}, + }, + } + + programs = append(programs, fentryProgram) + + kprobeProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + Type: bpfmaniov1alpha1.ProgTypeKprobe, + Kprobe: &bpfmaniov1alpha1.KprobeProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfKprobeFunctionName, + }, + AttachPoints: []bpfmaniov1alpha1.KprobeAttachInfo{ + { + FunctionName: kprobeFunctionName, + Offset: uint64(kprobeOffset), + RetProbe: kprobeRetprobe, + }, + }, + }, + } + + programs = append(programs, kprobeProgram) + App := &bpfmaniov1alpha1.BpfApplication{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -63,28 +95,7 @@ func TestBpfApplicationControllerCreate(t *testing.T) { Path: &bytecodePath, }, }, - Programs: []bpfmaniov1alpha1.BpfApplicationProgram{ - { - Type: bpfmaniov1alpha1.ProgTypeFentry, - Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ - BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ - BpfFunctionName: bpfFentryFunctionName, - }, - FunctionName: fentryFunctionName, - }, - }, - { - Type: bpfmaniov1alpha1.ProgTypeKprobe, - Kprobe: &bpfmaniov1alpha1.KprobeProgramInfo{ - BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ - BpfFunctionName: bpfKprobeFunctionName, - }, - FunctionName: kprobeFunctionName, - Offset: uint64(kprobeOffset), - RetProbe: kprobeRetprobe, - }, - }, - }, + Programs: programs, }, } diff --git a/controllers/bpfman-agent/common.go b/controllers/bpfman-agent/common.go index 9c93f7392..c232bef9e 100644 --- a/controllers/bpfman-agent/common.go +++ b/controllers/bpfman-agent/common.go @@ -880,7 +880,7 @@ func (r *ReconcilerCommon[T, TL]) reconcileProgram(ctx context.Context, // Determine if the MapOwnerSelector was set, and if so, see if the MapOwner // ID can be found. - mapOwnerStatus, err := r.processMapOwnerParam(ctx, rec, &rec.getBpfProgramCommon().MapOwnerSelector) + mapOwnerStatus, err := r.processMapOwnerParam(ctx, rec, &rec.getBpfProgramCommon().OldMapOwnerSelector) if err != nil { return internal.Requeue, fmt.Errorf("failed to determine map owner: %v", err) } diff --git a/controllers/bpfman-agent/fentry-program.go b/controllers/bpfman-agent/fentry-program.go index 4a6fed9c8..41fddb153 100644 --- a/controllers/bpfman-agent/fentry-program.go +++ b/controllers/bpfman-agent/fentry-program.go @@ -119,7 +119,7 @@ func (r *FentryProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfProgram{}, builder.WithPredicates(predicate.And( internal.BpfProgramTypePredicate(internal.FentryString), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Only trigger reconciliation if node labels change since that could diff --git a/controllers/bpfman-agent/fentry-program_test.go b/controllers/bpfman-agent/fentry-program_test.go index a2a4e0c52..b24d91d11 100644 --- a/controllers/bpfman-agent/fentry-program_test.go +++ b/controllers/bpfman-agent/fentry-program_test.go @@ -71,7 +71,8 @@ func TestFentryProgramControllerCreate(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - FunctionName: functionName, + FentryLoadInfo: bpfmaniov1alpha1.FentryLoadInfo{FunctionName: functionName}, + FentryAttachInfo: bpfmaniov1alpha1.FentryAttachInfo{Attach: true}, }, }, } diff --git a/controllers/bpfman-agent/fexit-program.go b/controllers/bpfman-agent/fexit-program.go index 2690aaf7b..7dd4784d6 100644 --- a/controllers/bpfman-agent/fexit-program.go +++ b/controllers/bpfman-agent/fexit-program.go @@ -119,7 +119,7 @@ func (r *FexitProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfProgram{}, builder.WithPredicates(predicate.And( internal.BpfProgramTypePredicate(internal.FexitString), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Only trigger reconciliation if node labels change since that could diff --git a/controllers/bpfman-agent/fexit-program_test.go b/controllers/bpfman-agent/fexit-program_test.go index 87812a029..505b515d9 100644 --- a/controllers/bpfman-agent/fexit-program_test.go +++ b/controllers/bpfman-agent/fexit-program_test.go @@ -71,7 +71,8 @@ func TestFexitProgramControllerCreate(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - FunctionName: functionName, + FexitLoadInfo: bpfmaniov1alpha1.FexitLoadInfo{FunctionName: functionName}, + FexitAttachInfo: bpfmaniov1alpha1.FexitAttachInfo{Attach: true}, }, }, } diff --git a/controllers/bpfman-agent/kprobe-program.go b/controllers/bpfman-agent/kprobe-program.go index fb8b9fa82..7fde7532d 100644 --- a/controllers/bpfman-agent/kprobe-program.go +++ b/controllers/bpfman-agent/kprobe-program.go @@ -119,7 +119,7 @@ func (r *KprobeProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfProgram{}, builder.WithPredicates(predicate.And( internal.BpfProgramTypePredicate(internal.Kprobe.String()), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Only trigger reconciliation if node labels change since that could @@ -136,9 +136,9 @@ func (r *KprobeProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *KprobeProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpfmaniov1alpha1.BpfProgramList, error) { progs := &bpfmaniov1alpha1.BpfProgramList{} - attachPoint := sanitize(r.currentKprobeProgram.Spec.FunctionName) + attachPoint := sanitize(r.currentKprobeProgram.Spec.AttachPoints[0].FunctionName) - annotations := map[string]string{internal.KprobeProgramFunction: r.currentKprobeProgram.Spec.FunctionName} + annotations := map[string]string{internal.KprobeProgramFunction: r.currentKprobeProgram.Spec.AttachPoints[0].FunctionName} prog, err := r.createBpfProgram(attachPoint, r, annotations) if err != nil { @@ -208,8 +208,8 @@ func (r *KprobeProgramReconciler) getLoadRequest(bpfProgram *bpfmaniov1alpha1.Bp Info: &gobpfman.AttachInfo_KprobeAttachInfo{ KprobeAttachInfo: &gobpfman.KprobeAttachInfo{ FnName: bpfProgram.Annotations[internal.KprobeProgramFunction], - Offset: r.currentKprobeProgram.Spec.Offset, - Retprobe: r.currentKprobeProgram.Spec.RetProbe, + Offset: r.currentKprobeProgram.Spec.AttachPoints[0].Offset, + Retprobe: r.currentKprobeProgram.Spec.AttachPoints[0].RetProbe, ContainerPid: &container_pid, }, }, diff --git a/controllers/bpfman-agent/kprobe-program_test.go b/controllers/bpfman-agent/kprobe-program_test.go index 7c477b1be..c14177c24 100644 --- a/controllers/bpfman-agent/kprobe-program_test.go +++ b/controllers/bpfman-agent/kprobe-program_test.go @@ -74,9 +74,13 @@ func TestKprobeProgramControllerCreate(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - FunctionName: functionName, - Offset: uint64(offset), - RetProbe: retprobe, + AttachPoints: []bpfmaniov1alpha1.KprobeAttachInfo{ + { + FunctionName: functionName, + Offset: uint64(offset), + RetProbe: retprobe, + }, + }, }, }, } diff --git a/controllers/bpfman-agent/tc-ns-program.go b/controllers/bpfman-agent/tc-ns-program.go index f0d9a136c..e2e5e1056 100644 --- a/controllers/bpfman-agent/tc-ns-program.go +++ b/controllers/bpfman-agent/tc-ns-program.go @@ -111,7 +111,7 @@ func (r *TcNsProgramReconciler) setCurrentProgram(program client.Object) error { return fmt.Errorf("failed to cast program to TcNsProgram") } - r.interfaces, err = getInterfaces(&r.currentTcNsProgram.Spec.InterfaceSelector, r.ourNode) + r.interfaces, err = getInterfaces(&r.currentTcNsProgram.Spec.AttachPoints[0].InterfaceSelector, r.ourNode) if err != nil { return fmt.Errorf("failed to get interfaces for TcNsProgram: %v", err) } @@ -133,7 +133,7 @@ func (r *TcNsProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfNsProgram{}, builder.WithPredicates(predicate.And( internal.BpfNsProgramTypePredicate(internal.Tc.String()), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Only trigger reconciliation if node labels change since that could @@ -161,8 +161,8 @@ func (r *TcNsProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bp containerInfo, err := r.Containers.GetContainers( ctx, r.getNamespace(), - r.currentTcNsProgram.Spec.Containers.Pods, - r.currentTcNsProgram.Spec.Containers.ContainerNames, + r.currentTcNsProgram.Spec.AttachPoints[0].Containers.Pods, + r.currentTcNsProgram.Spec.AttachPoints[0].Containers.ContainerNames, r.Logger, ) if err != nil { @@ -175,7 +175,7 @@ func (r *TcNsProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bp for _, iface := range r.interfaces { attachPoint := fmt.Sprintf("%s-%s-%s", iface, - r.currentTcNsProgram.Spec.Direction, + r.currentTcNsProgram.Spec.AttachPoints[0].Direction, "no-containers-on-node", ) @@ -198,7 +198,7 @@ func (r *TcNsProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bp for _, iface := range r.interfaces { attachPoint := fmt.Sprintf("%s-%s-%s-%s", iface, - r.currentTcNsProgram.Spec.Direction, + r.currentTcNsProgram.Spec.AttachPoints[0].Direction, container.podName, container.containerName, ) @@ -269,10 +269,10 @@ func (r *TcNsProgramReconciler) getLoadRequest(bpfProgram *bpfmaniov1alpha1.BpfN } attachInfo := &gobpfman.TCAttachInfo{ - Priority: r.currentTcNsProgram.Spec.Priority, + Priority: r.currentTcNsProgram.Spec.AttachPoints[0].Priority, Iface: bpfProgram.Annotations[internal.TcNsProgramInterface], - Direction: r.currentTcNsProgram.Spec.Direction, - ProceedOn: tcProceedOnToInt(r.currentTcNsProgram.Spec.ProceedOn), + Direction: r.currentTcNsProgram.Spec.AttachPoints[0].Direction, + ProceedOn: tcProceedOnToInt(r.currentTcNsProgram.Spec.AttachPoints[0].ProceedOn), } containerPidStr, ok := bpfProgram.Annotations[internal.TcNsContainerPid] diff --git a/controllers/bpfman-agent/tc-ns-program_test.go b/controllers/bpfman-agent/tc-ns-program_test.go index 3ed6a3df5..54429d3d1 100644 --- a/controllers/bpfman-agent/tc-ns-program_test.go +++ b/controllers/bpfman-agent/tc-ns-program_test.go @@ -66,6 +66,7 @@ func TestTcNsProgramControllerCreate(t *testing.T) { fakeContainerName, ) ) + // A TcNsProgram object with metadata and spec. tc := &bpfmaniov1alpha1.TcNsProgram{ ObjectMeta: metav1.ObjectMeta{ @@ -82,22 +83,26 @@ func TestTcNsProgramControllerCreate(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &[]string{fakeInt}, - }, - Priority: 0, - Direction: direction, - ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ - bpfmaniov1alpha1.TcProceedOnValue("pipe"), - bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), - }, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": fakePodName, + AttachPoints: []bpfmaniov1alpha1.TcNsAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{fakeInt}, + }, + Priority: 0, + Direction: direction, + ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ + bpfmaniov1alpha1.TcProceedOnValue("pipe"), + bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), + }, + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": fakePodName, + }, + }, + ContainerNames: &[]string{fakeContainerName}, }, }, - ContainerNames: &[]string{fakeContainerName}, }, }, }, @@ -276,6 +281,7 @@ func TestTcNsProgramControllerCreateMultiIntf(t *testing.T) { fakeContainerName, ) ) + // A TcNsProgram object with metadata and spec. tc := &bpfmaniov1alpha1.TcNsProgram{ ObjectMeta: metav1.ObjectMeta{ @@ -292,19 +298,24 @@ func TestTcNsProgramControllerCreateMultiIntf(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &fakeInts, - }, - Priority: 0, - Direction: direction, - ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ - bpfmaniov1alpha1.TcProceedOnValue("pipe"), - bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), - }, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": fakePodName, + AttachPoints: []bpfmaniov1alpha1.TcNsAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &fakeInts, + }, + Priority: 0, + Direction: direction, + ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ + bpfmaniov1alpha1.TcProceedOnValue("pipe"), + bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), + }, + + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": fakePodName, + }, + }, }, }, }, diff --git a/controllers/bpfman-agent/tc-program.go b/controllers/bpfman-agent/tc-program.go index 7baff7874..ba0b260bf 100644 --- a/controllers/bpfman-agent/tc-program.go +++ b/controllers/bpfman-agent/tc-program.go @@ -110,7 +110,7 @@ func (r *TcProgramReconciler) setCurrentProgram(program client.Object) error { return fmt.Errorf("failed to cast program to TcProgram") } - r.interfaces, err = getInterfaces(&r.currentTcProgram.Spec.InterfaceSelector, r.ourNode) + r.interfaces, err = getInterfaces(&r.currentTcProgram.Spec.AttachPoints[0].InterfaceSelector, r.ourNode) if err != nil { return fmt.Errorf("failed to get interfaces for TcProgram: %v", err) } @@ -166,7 +166,7 @@ func (r *TcProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfProgram{}, builder.WithPredicates(predicate.And( internal.BpfProgramTypePredicate(internal.Tc.String()), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Only trigger reconciliation if node labels change since that could @@ -189,15 +189,15 @@ func (r *TcProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *TcProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpfmaniov1alpha1.BpfProgramList, error) { progs := &bpfmaniov1alpha1.BpfProgramList{} - if r.currentTcProgram.Spec.Containers != nil { + if r.currentTcProgram.Spec.AttachPoints[0].Containers != nil { // There is a container selector, so see if there are any matching // containers on this node. containerInfo, err := r.Containers.GetContainers( ctx, - r.currentTcProgram.Spec.Containers.Namespace, - r.currentTcProgram.Spec.Containers.Pods, - r.currentTcProgram.Spec.Containers.ContainerNames, + r.currentTcProgram.Spec.AttachPoints[0].Containers.Namespace, + r.currentTcProgram.Spec.AttachPoints[0].Containers.Pods, + r.currentTcProgram.Spec.AttachPoints[0].Containers.ContainerNames, r.Logger, ) if err != nil { @@ -210,7 +210,7 @@ func (r *TcProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpfm for _, iface := range r.interfaces { attachPoint := fmt.Sprintf("%s-%s-%s", iface, - r.currentTcProgram.Spec.Direction, + r.currentTcProgram.Spec.AttachPoints[0].Direction, "no-containers-on-node", ) @@ -233,7 +233,7 @@ func (r *TcProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpfm for _, iface := range r.interfaces { attachPoint := fmt.Sprintf("%s-%s-%s-%s", iface, - r.currentTcProgram.Spec.Direction, + r.currentTcProgram.Spec.AttachPoints[0].Direction, container.podName, container.containerName, ) @@ -254,7 +254,7 @@ func (r *TcProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpfm } } else { for _, iface := range r.interfaces { - attachPoint := iface + "-" + r.currentTcProgram.Spec.Direction + attachPoint := iface + "-" + r.currentTcProgram.Spec.AttachPoints[0].Direction annotations := map[string]string{internal.TcProgramInterface: iface} prog, err := r.createBpfProgram(attachPoint, r, annotations) @@ -317,10 +317,10 @@ func (r *TcProgramReconciler) getLoadRequest(bpfProgram *bpfmaniov1alpha1.BpfPro } attachInfo := &gobpfman.TCAttachInfo{ - Priority: r.currentTcProgram.Spec.Priority, + Priority: r.currentTcProgram.Spec.AttachPoints[0].Priority, Iface: bpfProgram.Annotations[internal.TcProgramInterface], - Direction: r.currentTcProgram.Spec.Direction, - ProceedOn: tcProceedOnToInt(r.currentTcProgram.Spec.ProceedOn), + Direction: r.currentTcProgram.Spec.AttachPoints[0].Direction, + ProceedOn: tcProceedOnToInt(r.currentTcProgram.Spec.AttachPoints[0].ProceedOn), } containerPidStr, ok := bpfProgram.Annotations[internal.TcContainerPid] diff --git a/controllers/bpfman-agent/tc-program_test.go b/controllers/bpfman-agent/tc-program_test.go index f966b2a08..1d1edb2e0 100644 --- a/controllers/bpfman-agent/tc-program_test.go +++ b/controllers/bpfman-agent/tc-program_test.go @@ -73,14 +73,18 @@ func TestTcProgramControllerCreate(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &[]string{fakeInt}, - }, - Priority: 0, - Direction: direction, - ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ - bpfmaniov1alpha1.TcProceedOnValue("pipe"), - bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), + AttachPoints: []bpfmaniov1alpha1.TcAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{fakeInt}, + }, + Priority: 0, + Direction: direction, + ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ + bpfmaniov1alpha1.TcProceedOnValue("pipe"), + bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), + }, + }, }, }, }, @@ -233,6 +237,7 @@ func TestTcProgramControllerCreateMultiIntf(t *testing.T) { fakeUID0 = "ef71d42c-aa21-48e8-a697-82391d801a80" fakeUID1 = "ef71d42c-aa21-48e8-a697-82391d801a81" ) + // A TcProgram object with metadata and spec. tc := &bpfmaniov1alpha1.TcProgram{ ObjectMeta: metav1.ObjectMeta{ @@ -249,14 +254,18 @@ func TestTcProgramControllerCreateMultiIntf(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &fakeInts, - }, - Priority: 0, - Direction: direction, - ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ - bpfmaniov1alpha1.TcProceedOnValue("pipe"), - bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), + AttachPoints: []bpfmaniov1alpha1.TcAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &fakeInts, + }, + Priority: 0, + Direction: direction, + ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ + bpfmaniov1alpha1.TcProceedOnValue("pipe"), + bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), + }, + }, }, }, }, diff --git a/controllers/bpfman-agent/tcx-ns-program.go b/controllers/bpfman-agent/tcx-ns-program.go index 7546fb7ba..7f153cfa1 100644 --- a/controllers/bpfman-agent/tcx-ns-program.go +++ b/controllers/bpfman-agent/tcx-ns-program.go @@ -111,7 +111,7 @@ func (r *TcxNsProgramReconciler) setCurrentProgram(program client.Object) error return fmt.Errorf("failed to cast program to TcxNsProgram") } - r.interfaces, err = getInterfaces(&r.currentTcxNsProgram.Spec.InterfaceSelector, r.ourNode) + r.interfaces, err = getInterfaces(&r.currentTcxNsProgram.Spec.AttachPoints[0].InterfaceSelector, r.ourNode) if err != nil { return fmt.Errorf("failed to get interfaces for TcxNsProgram: %v", err) } @@ -133,7 +133,7 @@ func (r *TcxNsProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfNsProgram{}, builder.WithPredicates(predicate.And( internal.BpfNsProgramTypePredicate(internal.TcxString), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Only trigger reconciliation if node labels change since that could @@ -161,8 +161,8 @@ func (r *TcxNsProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*b containerInfo, err := r.Containers.GetContainers( ctx, r.getNamespace(), - r.currentTcxNsProgram.Spec.Containers.Pods, - r.currentTcxNsProgram.Spec.Containers.ContainerNames, + r.currentTcxNsProgram.Spec.AttachPoints[0].Containers.Pods, + r.currentTcxNsProgram.Spec.AttachPoints[0].Containers.ContainerNames, r.Logger, ) if err != nil { @@ -175,7 +175,7 @@ func (r *TcxNsProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*b for _, iface := range r.interfaces { attachPoint := fmt.Sprintf("%s-%s-%s", iface, - r.currentTcxNsProgram.Spec.Direction, + r.currentTcxNsProgram.Spec.AttachPoints[0].Direction, "no-containers-on-node", ) @@ -198,7 +198,7 @@ func (r *TcxNsProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*b for _, iface := range r.interfaces { attachPoint := fmt.Sprintf("%s-%s-%s-%s", iface, - r.currentTcxNsProgram.Spec.Direction, + r.currentTcxNsProgram.Spec.AttachPoints[0].Direction, container.podName, container.containerName, ) @@ -269,9 +269,9 @@ func (r *TcxNsProgramReconciler) getLoadRequest(bpfProgram *bpfmaniov1alpha1.Bpf } attachInfo := &gobpfman.TCXAttachInfo{ - Priority: r.currentTcxNsProgram.Spec.Priority, + Priority: r.currentTcxNsProgram.Spec.AttachPoints[0].Priority, Iface: bpfProgram.Annotations[internal.TcxNsProgramInterface], - Direction: r.currentTcxNsProgram.Spec.Direction, + Direction: r.currentTcxNsProgram.Spec.AttachPoints[0].Direction, } containerPidStr, ok := bpfProgram.Annotations[internal.TcxNsContainerPid] diff --git a/controllers/bpfman-agent/tcx-ns-program_test.go b/controllers/bpfman-agent/tcx-ns-program_test.go index 3495407ac..6d56bef26 100644 --- a/controllers/bpfman-agent/tcx-ns-program_test.go +++ b/controllers/bpfman-agent/tcx-ns-program_test.go @@ -83,15 +83,21 @@ func TestTcxNsProgramControllerCreate(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &[]string{fakeInt}, - }, - Priority: 0, - Direction: direction, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "test", + AttachPoints: []bpfmaniov1alpha1.TcxNsAttachInfo{ + + { + + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{fakeInt}, + }, + Priority: 0, + Direction: direction, + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "test", + }, + }, }, }, }, @@ -201,7 +207,7 @@ func TestTcxNsProgramControllerCreate(t *testing.T) { Info: &gobpfman.AttachInfo_TcxAttachInfo{ TcxAttachInfo: &gobpfman.TCXAttachInfo{ Iface: fakeInt, - Priority: tcx.Spec.Priority, + Priority: tcx.Spec.AttachPoints[0].Priority, Direction: direction, Netns: &netns, }, @@ -288,15 +294,19 @@ func TestTcxNsProgramControllerCreateMultiIntf(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &fakeInts, - }, - Priority: 10, - Direction: direction, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "test", + AttachPoints: []bpfmaniov1alpha1.TcxNsAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &fakeInts, + }, + Priority: 10, + Direction: direction, + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "test", + }, + }, }, }, }, @@ -457,7 +467,7 @@ func TestTcxNsProgramControllerCreateMultiIntf(t *testing.T) { Info: &gobpfman.AttachInfo_TcxAttachInfo{ TcxAttachInfo: &gobpfman.TCXAttachInfo{ Iface: fakeInts[0], - Priority: tcx.Spec.Priority, + Priority: tcx.Spec.AttachPoints[0].Priority, Direction: direction, Netns: &netns, }, @@ -479,7 +489,7 @@ func TestTcxNsProgramControllerCreateMultiIntf(t *testing.T) { Info: &gobpfman.AttachInfo_TcxAttachInfo{ TcxAttachInfo: &gobpfman.TCXAttachInfo{ Iface: fakeInts[1], - Priority: tcx.Spec.Priority, + Priority: tcx.Spec.AttachPoints[0].Priority, Direction: direction, Netns: &netns, }, diff --git a/controllers/bpfman-agent/tcx-program.go b/controllers/bpfman-agent/tcx-program.go index 0a6c4ed06..0a3793d28 100644 --- a/controllers/bpfman-agent/tcx-program.go +++ b/controllers/bpfman-agent/tcx-program.go @@ -110,7 +110,7 @@ func (r *TcxProgramReconciler) setCurrentProgram(program client.Object) error { return fmt.Errorf("failed to cast program to TcxProgram") } - r.interfaces, err = getInterfaces(&r.currentTcxProgram.Spec.InterfaceSelector, r.ourNode) + r.interfaces, err = getInterfaces(&r.currentTcxProgram.Spec.AttachPoints[0].InterfaceSelector, r.ourNode) if err != nil { return fmt.Errorf("failed to get interfaces for TcxProgram: %v", err) } @@ -132,7 +132,7 @@ func (r *TcxProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfProgram{}, builder.WithPredicates(predicate.And( internal.BpfProgramTypePredicate(internal.TcxString), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Only trigger reconciliation if node labels change since that could @@ -155,15 +155,15 @@ func (r *TcxProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *TcxProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpfmaniov1alpha1.BpfProgramList, error) { progs := &bpfmaniov1alpha1.BpfProgramList{} - if r.currentTcxProgram.Spec.Containers != nil { + if r.currentTcxProgram.Spec.AttachPoints[0].Containers != nil { // There is a container selector, so see if there are any matching // containers on this node. containerInfo, err := r.Containers.GetContainers( ctx, - r.currentTcxProgram.Spec.Containers.Namespace, - r.currentTcxProgram.Spec.Containers.Pods, - r.currentTcxProgram.Spec.Containers.ContainerNames, + r.currentTcxProgram.Spec.AttachPoints[0].Containers.Namespace, + r.currentTcxProgram.Spec.AttachPoints[0].Containers.Pods, + r.currentTcxProgram.Spec.AttachPoints[0].Containers.ContainerNames, r.Logger, ) if err != nil { @@ -176,7 +176,7 @@ func (r *TcxProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpf for _, iface := range r.interfaces { attachPoint := fmt.Sprintf("%s-%s-%s", iface, - r.currentTcxProgram.Spec.Direction, + r.currentTcxProgram.Spec.AttachPoints[0].Direction, "no-containers-on-node", ) @@ -199,7 +199,7 @@ func (r *TcxProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpf for _, iface := range r.interfaces { attachPoint := fmt.Sprintf("%s-%s-%s-%s", iface, - r.currentTcxProgram.Spec.Direction, + r.currentTcxProgram.Spec.AttachPoints[0].Direction, container.podName, container.containerName, ) @@ -220,7 +220,7 @@ func (r *TcxProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpf } } else { for _, iface := range r.interfaces { - attachPoint := iface + "-" + r.currentTcxProgram.Spec.Direction + attachPoint := iface + "-" + r.currentTcxProgram.Spec.AttachPoints[0].Direction annotations := map[string]string{internal.TcxProgramInterface: iface} prog, err := r.createBpfProgram(attachPoint, r, annotations) @@ -283,9 +283,9 @@ func (r *TcxProgramReconciler) getLoadRequest(bpfProgram *bpfmaniov1alpha1.BpfPr } attachInfo := &gobpfman.TCXAttachInfo{ - Priority: r.currentTcxProgram.Spec.Priority, + Priority: r.currentTcxProgram.Spec.AttachPoints[0].Priority, Iface: bpfProgram.Annotations[internal.TcxProgramInterface], - Direction: r.currentTcxProgram.Spec.Direction, + Direction: r.currentTcxProgram.Spec.AttachPoints[0].Direction, } containerPidStr, ok := bpfProgram.Annotations[internal.TcxContainerPid] diff --git a/controllers/bpfman-agent/tcx-program_test.go b/controllers/bpfman-agent/tcx-program_test.go index 7b343ff4d..461116dfa 100644 --- a/controllers/bpfman-agent/tcx-program_test.go +++ b/controllers/bpfman-agent/tcx-program_test.go @@ -73,11 +73,15 @@ func TestTcxProgramControllerCreate(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &[]string{fakeInt}, + AttachPoints: []bpfmaniov1alpha1.TcxAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{fakeInt}, + }, + Priority: 0, + Direction: direction, + }, }, - Priority: 0, - Direction: direction, }, }, } @@ -172,7 +176,7 @@ func TestTcxProgramControllerCreate(t *testing.T) { Info: &gobpfman.AttachInfo_TcxAttachInfo{ TcxAttachInfo: &gobpfman.TCXAttachInfo{ Iface: fakeInt, - Priority: tcx.Spec.Priority, + Priority: tcx.Spec.AttachPoints[0].Priority, Direction: direction, }, }, @@ -244,11 +248,15 @@ func TestTcxProgramControllerCreateMultiIntf(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &fakeInts, + AttachPoints: []bpfmaniov1alpha1.TcxAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &fakeInts, + }, + Priority: 10, + Direction: direction, + }, }, - Priority: 10, - Direction: direction, }, }, } @@ -394,7 +402,7 @@ func TestTcxProgramControllerCreateMultiIntf(t *testing.T) { Info: &gobpfman.AttachInfo_TcxAttachInfo{ TcxAttachInfo: &gobpfman.TCXAttachInfo{ Iface: fakeInts[0], - Priority: tcx.Spec.Priority, + Priority: tcx.Spec.AttachPoints[0].Priority, Direction: direction, }, }, @@ -415,7 +423,7 @@ func TestTcxProgramControllerCreateMultiIntf(t *testing.T) { Info: &gobpfman.AttachInfo_TcxAttachInfo{ TcxAttachInfo: &gobpfman.TCXAttachInfo{ Iface: fakeInts[1], - Priority: tcx.Spec.Priority, + Priority: tcx.Spec.AttachPoints[0].Priority, Direction: direction, }, }, diff --git a/controllers/bpfman-agent/tracepoint-program.go b/controllers/bpfman-agent/tracepoint-program.go index 7855399fd..cf8cd1013 100644 --- a/controllers/bpfman-agent/tracepoint-program.go +++ b/controllers/bpfman-agent/tracepoint-program.go @@ -119,7 +119,7 @@ func (r *TracepointProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfProgram{}, builder.WithPredicates(predicate.And( internal.BpfProgramTypePredicate(internal.Tracepoint.String()), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Only trigger reconciliation if node labels change since that could @@ -136,18 +136,17 @@ func (r *TracepointProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *TracepointProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpfmaniov1alpha1.BpfProgramList, error) { progs := &bpfmaniov1alpha1.BpfProgramList{} - for _, tracepoint := range r.currentTracepointProgram.Spec.Names { - attachPoint := sanitize(tracepoint) - annotations := map[string]string{internal.TracepointProgramTracepoint: tracepoint} + tracepoint := r.currentTracepointProgram.Spec.AttachPoints[0].Name + attachPoint := sanitize(tracepoint) + annotations := map[string]string{internal.TracepointProgramTracepoint: tracepoint} - prog, err := r.createBpfProgram(attachPoint, r, annotations) - if err != nil { - return nil, fmt.Errorf("failed to create BpfProgram %s: %v", attachPoint, err) - } - - progs.Items = append(progs.Items, *prog) + prog, err := r.createBpfProgram(attachPoint, r, annotations) + if err != nil { + return nil, fmt.Errorf("failed to create BpfProgram %s: %v", attachPoint, err) } + progs.Items = append(progs.Items, *prog) + return progs, nil } diff --git a/controllers/bpfman-agent/tracepoint-program_test.go b/controllers/bpfman-agent/tracepoint-program_test.go index 876fb5bf6..6b47190a4 100644 --- a/controllers/bpfman-agent/tracepoint-program_test.go +++ b/controllers/bpfman-agent/tracepoint-program_test.go @@ -71,7 +71,7 @@ func TestTracepointProgramControllerCreate(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - Names: []string{tracepointName}, + AttachPoints: []bpfmaniov1alpha1.TracepointAttachInfo{{Name: tracepointName}}, }, }, } diff --git a/controllers/bpfman-agent/uprobe-ns-program.go b/controllers/bpfman-agent/uprobe-ns-program.go index a6ab77581..5961b1d07 100644 --- a/controllers/bpfman-agent/uprobe-ns-program.go +++ b/controllers/bpfman-agent/uprobe-ns-program.go @@ -121,7 +121,7 @@ func (r *UprobeNsProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfNsProgram{}, builder.WithPredicates(predicate.And( internal.BpfNsProgramTypePredicate(internal.UprobeString), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Trigger reconciliation if node labels change since that could make @@ -145,15 +145,15 @@ func (r *UprobeNsProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *UprobeNsProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpfmaniov1alpha1.BpfNsProgramList, error) { progs := &bpfmaniov1alpha1.BpfNsProgramList{} - sanitizedUprobe := sanitize(r.currentUprobeNsProgram.Spec.Target) + "-" + sanitize(r.currentUprobeNsProgram.Spec.FunctionName) + sanitizedUprobe := sanitize(r.currentUprobeNsProgram.Spec.AttachPoints[0].Target) + "-" + sanitize(r.currentUprobeNsProgram.Spec.AttachPoints[0].FunctionName) // There is a container selector, so see if there are any matching // containers on this node. containerInfo, err := r.Containers.GetContainers( ctx, r.getNamespace(), - r.currentUprobeNsProgram.Spec.Containers.Pods, - r.currentUprobeNsProgram.Spec.Containers.ContainerNames, + r.currentUprobeNsProgram.Spec.AttachPoints[0].Containers.Pods, + r.currentUprobeNsProgram.Spec.AttachPoints[0].Containers.ContainerNames, r.Logger, ) if err != nil { @@ -164,7 +164,7 @@ func (r *UprobeNsProgramReconciler) getExpectedBpfPrograms(ctx context.Context) // select any containers on this node. annotations := map[string]string{ - internal.UprobeNsProgramTarget: r.currentUprobeNsProgram.Spec.Target, + internal.UprobeNsProgramTarget: r.currentUprobeNsProgram.Spec.AttachPoints[0].Target, internal.UprobeNsNoContainersOnNode: "true", } @@ -182,7 +182,7 @@ func (r *UprobeNsProgramReconciler) getExpectedBpfPrograms(ctx context.Context) for i := range *containerInfo { container := (*containerInfo)[i] - annotations := map[string]string{internal.UprobeNsProgramTarget: r.currentUprobeNsProgram.Spec.Target} + annotations := map[string]string{internal.UprobeNsProgramTarget: r.currentUprobeNsProgram.Spec.AttachPoints[0].Target} annotations[internal.UprobeNsContainerPid] = strconv.FormatInt(container.pid, 10) attachPoint := fmt.Sprintf("%s-%s-%s", @@ -268,10 +268,10 @@ func (r *UprobeNsProgramReconciler) getLoadRequest(bpfProgram *bpfmaniov1alpha1. } uprobeAttachInfo = &gobpfman.UprobeAttachInfo{ - FnName: &r.currentUprobeNsProgram.Spec.FunctionName, - Offset: r.currentUprobeNsProgram.Spec.Offset, + FnName: &r.currentUprobeNsProgram.Spec.AttachPoints[0].FunctionName, + Offset: r.currentUprobeNsProgram.Spec.AttachPoints[0].Offset, Target: bpfProgram.Annotations[internal.UprobeNsProgramTarget], - Retprobe: r.currentUprobeNsProgram.Spec.RetProbe, + Retprobe: r.currentUprobeNsProgram.Spec.AttachPoints[0].RetProbe, } if hasContainerPid { diff --git a/controllers/bpfman-agent/uprobe-ns-program_test.go b/controllers/bpfman-agent/uprobe-ns-program_test.go index 4af32f64b..d8ab9fa2e 100644 --- a/controllers/bpfman-agent/uprobe-ns-program_test.go +++ b/controllers/bpfman-agent/uprobe-ns-program_test.go @@ -84,14 +84,18 @@ func TestUprobeNsProgramControllerCreate(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - FunctionName: functionName, - Target: target, - Offset: uint64(offset), - RetProbe: retprobe, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": fakePodName, + AttachPoints: []bpfmaniov1alpha1.UprobeNsAttachInfo{ + { + FunctionName: functionName, + Target: target, + Offset: uint64(offset), + RetProbe: retprobe, + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": fakePodName, + }, + }, }, }, }, diff --git a/controllers/bpfman-agent/uprobe-program.go b/controllers/bpfman-agent/uprobe-program.go index 20875729f..556d2d4af 100644 --- a/controllers/bpfman-agent/uprobe-program.go +++ b/controllers/bpfman-agent/uprobe-program.go @@ -120,7 +120,7 @@ func (r *UprobeProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfProgram{}, builder.WithPredicates(predicate.And( internal.BpfProgramTypePredicate(internal.UprobeString), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Trigger reconciliation if node labels change since that could make @@ -144,17 +144,18 @@ func (r *UprobeProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *UprobeProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpfmaniov1alpha1.BpfProgramList, error) { progs := &bpfmaniov1alpha1.BpfProgramList{} - sanitizedUprobe := sanitize(r.currentUprobeProgram.Spec.Target) + "-" + sanitize(r.currentUprobeProgram.Spec.FunctionName) + sanitizedUprobe := sanitize(r.currentUprobeProgram.Spec.AttachPoints[0].Target) + "-" + + sanitize(r.currentUprobeProgram.Spec.AttachPoints[0].FunctionName) - if r.currentUprobeProgram.Spec.Containers != nil { + if r.currentUprobeProgram.Spec.AttachPoints[0].Containers != nil { // There is a container selector, so see if there are any matching // containers on this node. containerInfo, err := r.Containers.GetContainers( ctx, - r.currentUprobeProgram.Spec.Containers.Namespace, - r.currentUprobeProgram.Spec.Containers.Pods, - r.currentUprobeProgram.Spec.Containers.ContainerNames, + r.currentUprobeProgram.Spec.AttachPoints[0].Containers.Namespace, + r.currentUprobeProgram.Spec.AttachPoints[0].Containers.Pods, + r.currentUprobeProgram.Spec.AttachPoints[0].Containers.ContainerNames, r.Logger, ) if err != nil { @@ -165,7 +166,7 @@ func (r *UprobeProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (* // select any containers on this node. annotations := map[string]string{ - internal.UprobeProgramTarget: r.currentUprobeProgram.Spec.Target, + internal.UprobeProgramTarget: r.currentUprobeProgram.Spec.AttachPoints[0].Target, internal.UprobeNoContainersOnNode: "true", } @@ -183,7 +184,7 @@ func (r *UprobeProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (* for i := range *containerInfo { container := (*containerInfo)[i] - annotations := map[string]string{internal.UprobeProgramTarget: r.currentUprobeProgram.Spec.Target} + annotations := map[string]string{internal.UprobeProgramTarget: r.currentUprobeProgram.Spec.AttachPoints[0].Target} annotations[internal.UprobeContainerPid] = strconv.FormatInt(container.pid, 10) attachPoint := fmt.Sprintf("%s-%s-%s", @@ -201,7 +202,7 @@ func (r *UprobeProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (* } } } else { - annotations := map[string]string{internal.UprobeProgramTarget: r.currentUprobeProgram.Spec.Target} + annotations := map[string]string{internal.UprobeProgramTarget: r.currentUprobeProgram.Spec.AttachPoints[0].Target} attachPoint := sanitizedUprobe @@ -281,10 +282,10 @@ func (r *UprobeProgramReconciler) getLoadRequest(bpfProgram *bpfmaniov1alpha1.Bp } uprobeAttachInfo = &gobpfman.UprobeAttachInfo{ - FnName: &r.currentUprobeProgram.Spec.FunctionName, - Offset: r.currentUprobeProgram.Spec.Offset, + FnName: &r.currentUprobeProgram.Spec.AttachPoints[0].FunctionName, + Offset: r.currentUprobeProgram.Spec.AttachPoints[0].Offset, Target: bpfProgram.Annotations[internal.UprobeProgramTarget], - Retprobe: r.currentUprobeProgram.Spec.RetProbe, + Retprobe: r.currentUprobeProgram.Spec.AttachPoints[0].RetProbe, } if hasContainerPid { diff --git a/controllers/bpfman-agent/uprobe-program_test.go b/controllers/bpfman-agent/uprobe-program_test.go index 36abeaa15..fbe3c9912 100644 --- a/controllers/bpfman-agent/uprobe-program_test.go +++ b/controllers/bpfman-agent/uprobe-program_test.go @@ -75,10 +75,14 @@ func TestUprobeProgramControllerCreate(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - FunctionName: functionName, - Target: target, - Offset: uint64(offset), - RetProbe: retprobe, + AttachPoints: []bpfmaniov1alpha1.UprobeAttachInfo{ + { + FunctionName: functionName, + Target: target, + Offset: uint64(offset), + RetProbe: retprobe, + }, + }, }, }, } @@ -242,6 +246,16 @@ func TestUprobeProgramControllerCreateContainer(t *testing.T) { Pods: metav1.LabelSelector{}, } + attachPoints := []bpfmaniov1alpha1.UprobeAttachInfo{ + { + FunctionName: functionName, + Target: target, + Offset: uint64(offset), + RetProbe: retprobe, + Containers: &containerSelector, + }, + } + // A UprobeProgram object with metadata and spec. Uprobe := &bpfmaniov1alpha1.UprobeProgram{ ObjectMeta: metav1.ObjectMeta{ @@ -258,12 +272,7 @@ func TestUprobeProgramControllerCreateContainer(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - FunctionName: functionName, - Target: target, - Offset: uint64(offset), - RetProbe: retprobe, - Containers: &containerSelector, - }, + AttachPoints: attachPoints}, }, } diff --git a/controllers/bpfman-agent/xdp-ns-program.go b/controllers/bpfman-agent/xdp-ns-program.go index e87551909..fd34e0669 100644 --- a/controllers/bpfman-agent/xdp-ns-program.go +++ b/controllers/bpfman-agent/xdp-ns-program.go @@ -110,7 +110,7 @@ func (r *XdpNsProgramReconciler) setCurrentProgram(program client.Object) error return fmt.Errorf("failed to cast program to XdpNsProgram") } - r.interfaces, err = getInterfaces(&r.currentXdpNsProgram.Spec.InterfaceSelector, r.ourNode) + r.interfaces, err = getInterfaces(&r.currentXdpNsProgram.Spec.AttachPoints[0].InterfaceSelector, r.ourNode) if err != nil { return fmt.Errorf("failed to get interfaces for XdpNsProgram: %v", err) } @@ -133,7 +133,7 @@ func (r *XdpNsProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfNsProgram{}, builder.WithPredicates(predicate.And( internal.BpfNsProgramTypePredicate(internal.Xdp.String()), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Only trigger reconciliation if node labels change since that could @@ -161,8 +161,8 @@ func (r *XdpNsProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*b containerInfo, err := r.Containers.GetContainers( ctx, r.getNamespace(), - r.currentXdpNsProgram.Spec.Containers.Pods, - r.currentXdpNsProgram.Spec.Containers.ContainerNames, + r.currentXdpNsProgram.Spec.AttachPoints[0].Containers.Pods, + r.currentXdpNsProgram.Spec.AttachPoints[0].Containers.ContainerNames, r.Logger, ) if err != nil { @@ -266,9 +266,9 @@ func (r *XdpNsProgramReconciler) getLoadRequest(bpfProgram *bpfmaniov1alpha1.Bpf } attachInfo := &gobpfman.XDPAttachInfo{ - Priority: r.currentXdpNsProgram.Spec.Priority, + Priority: r.currentXdpNsProgram.Spec.AttachPoints[0].Priority, Iface: bpfProgram.Annotations[internal.XdpNsProgramInterface], - ProceedOn: xdpProceedOnToInt(r.currentXdpNsProgram.Spec.ProceedOn), + ProceedOn: xdpProceedOnToInt(r.currentXdpNsProgram.Spec.AttachPoints[0].ProceedOn), } containerPidStr, ok := bpfProgram.Annotations[internal.XdpNsContainerPid] diff --git a/controllers/bpfman-agent/xdp-ns-program_test.go b/controllers/bpfman-agent/xdp-ns-program_test.go index 316f86318..86cc476ab 100644 --- a/controllers/bpfman-agent/xdp-ns-program_test.go +++ b/controllers/bpfman-agent/xdp-ns-program_test.go @@ -101,17 +101,21 @@ func xdpNsProgramControllerCreate(t *testing.T, multiInterface bool, multiCondit BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &fakeInts, - }, - Priority: 0, - ProceedOn: []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), - bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return"), - }, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": fakePodName, + AttachPoints: []bpfmaniov1alpha1.XdpNsAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &fakeInts, + }, + Priority: 0, + ProceedOn: []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), + bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return"), + }, + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": fakePodName, + }, + }, }, }, }, diff --git a/controllers/bpfman-agent/xdp-program.go b/controllers/bpfman-agent/xdp-program.go index 07648ac7c..4df01909a 100644 --- a/controllers/bpfman-agent/xdp-program.go +++ b/controllers/bpfman-agent/xdp-program.go @@ -109,7 +109,7 @@ func (r *XdpProgramReconciler) setCurrentProgram(program client.Object) error { return fmt.Errorf("failed to cast program to XdpProgram") } - r.interfaces, err = getInterfaces(&r.currentXdpProgram.Spec.InterfaceSelector, r.ourNode) + r.interfaces, err = getInterfaces(&r.currentXdpProgram.Spec.AttachPoints[0].InterfaceSelector, r.ourNode) if err != nil { return fmt.Errorf("failed to get interfaces for XdpProgram: %v", err) } @@ -151,7 +151,7 @@ func (r *XdpProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&bpfmaniov1alpha1.BpfProgram{}, builder.WithPredicates(predicate.And( internal.BpfProgramTypePredicate(internal.Xdp.String()), - internal.BpfProgramNodePredicate(r.NodeName)), + internal.BpfNodePredicate(r.NodeName)), ), ). // Only trigger reconciliation if node labels change since that could @@ -174,15 +174,15 @@ func (r *XdpProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *XdpProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpfmaniov1alpha1.BpfProgramList, error) { progs := &bpfmaniov1alpha1.BpfProgramList{} - if r.currentXdpProgram.Spec.Containers != nil { + if r.currentXdpProgram.Spec.AttachPoints[0].Containers != nil { // There is a container selector, so see if there are any matching // containers on this node. containerInfo, err := r.Containers.GetContainers( ctx, - r.currentXdpProgram.Spec.Containers.Namespace, - r.currentXdpProgram.Spec.Containers.Pods, - r.currentXdpProgram.Spec.Containers.ContainerNames, + r.currentXdpProgram.Spec.AttachPoints[0].Containers.Namespace, + r.currentXdpProgram.Spec.AttachPoints[0].Containers.Pods, + r.currentXdpProgram.Spec.AttachPoints[0].Containers.ContainerNames, r.Logger, ) if err != nil { @@ -299,9 +299,9 @@ func (r *XdpProgramReconciler) getLoadRequest(bpfProgram *bpfmaniov1alpha1.BpfPr } attachInfo := &gobpfman.XDPAttachInfo{ - Priority: r.currentXdpProgram.Spec.Priority, + Priority: r.currentXdpProgram.Spec.AttachPoints[0].Priority, Iface: bpfProgram.Annotations[internal.XdpProgramInterface], - ProceedOn: xdpProceedOnToInt(r.currentXdpProgram.Spec.ProceedOn), + ProceedOn: xdpProceedOnToInt(r.currentXdpProgram.Spec.AttachPoints[0].ProceedOn), } containerPidStr, ok := bpfProgram.Annotations[internal.XdpContainerPid] diff --git a/controllers/bpfman-agent/xdp-program_test.go b/controllers/bpfman-agent/xdp-program_test.go index e6378758c..315f50cb2 100644 --- a/controllers/bpfman-agent/xdp-program_test.go +++ b/controllers/bpfman-agent/xdp-program_test.go @@ -88,12 +88,16 @@ func xdpProgramControllerCreate(t *testing.T, multiInterface bool, multiConditio BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &fakeInts, - }, - Priority: 0, - ProceedOn: []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), - bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return"), + AttachPoints: []bpfmaniov1alpha1.XdpAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &fakeInts, + }, + Priority: 0, + ProceedOn: []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), + bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return"), + }, + }, }, }, }, diff --git a/controllers/bpfman-operator/application-ns-program_test.go b/controllers/bpfman-operator/application-ns-program_test.go index 770064549..1b387d290 100644 --- a/controllers/bpfman-operator/application-ns-program_test.go +++ b/controllers/bpfman-operator/application-ns-program_test.go @@ -79,14 +79,18 @@ func appNsProgramReconcile(t *testing.T, multiCondition bool) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfTcFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &[]string{tcFakeInt}, - }, - Priority: 0, - Direction: tcDirection, - ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ - bpfmaniov1alpha1.TcProceedOnValue("pipe"), - bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), + AttachPoints: []bpfmaniov1alpha1.TcNsAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{tcFakeInt}, + }, + Priority: 0, + Direction: tcDirection, + ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ + bpfmaniov1alpha1.TcProceedOnValue("pipe"), + bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), + }, + }, }, }, }, @@ -96,20 +100,22 @@ func appNsProgramReconcile(t *testing.T, multiCondition bool) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfUprobeFunctionName, }, - FunctionName: uprobeFunctionName, - Target: uprobeTarget, - Offset: uint64(uprobeOffset), - RetProbe: uprobeRetprobe, - }, - /* - Containers: &bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "test", - }, + AttachPoints: []bpfmaniov1alpha1.UprobeNsAttachInfo{ + { + FunctionName: uprobeFunctionName, + Target: uprobeTarget, + Offset: uint64(uprobeOffset), + RetProbe: uprobeRetprobe, + // Containers: bpfmaniov1alpha1.ContainerNsSelector{ + // Pods: metav1.LabelSelector{ + // MatchLabels: map[string]string{ + // "app": "test", + // }, + // }, + // }, }, }, - */ + }, }, { Type: bpfmaniov1alpha1.ProgTypeXDP, @@ -117,17 +123,21 @@ func appNsProgramReconcile(t *testing.T, multiCondition bool) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfXdpFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &[]string{xdpFakeInt}, - }, - Priority: 0, - ProceedOn: []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), - bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return"), - }, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "test", + AttachPoints: []bpfmaniov1alpha1.XdpNsAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{xdpFakeInt}, + }, + Priority: 0, + ProceedOn: []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), + bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return"), + }, + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "test", + }, + }, }, }, }, diff --git a/controllers/bpfman-operator/application-program_test.go b/controllers/bpfman-operator/application-program_test.go index a2f3d2a25..80b4001f4 100644 --- a/controllers/bpfman-operator/application-program_test.go +++ b/controllers/bpfman-operator/application-program_test.go @@ -56,7 +56,58 @@ func appProgramReconcile(t *testing.T, multiCondition bool) { ctx = context.TODO() bpfProgName = fmt.Sprintf("%s-%s", name, fakeNode.Name) ) + // A AppProgram object with metadata and spec. + + programs := []bpfmaniov1alpha1.BpfApplicationProgram{} + + fentryProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + Type: bpfmaniov1alpha1.ProgTypeFentry, + Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfFentryFunctionName, + }, + FentryLoadInfo: bpfmaniov1alpha1.FentryLoadInfo{FunctionName: functionFentryName}, + FentryAttachInfo: bpfmaniov1alpha1.FentryAttachInfo{Attach: true}, + }, + } + + programs = append(programs, fentryProgram) + + kprobeProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + Type: bpfmaniov1alpha1.ProgTypeKprobe, + Kprobe: &bpfmaniov1alpha1.KprobeProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfKprobeFunctionName, + }, + AttachPoints: []bpfmaniov1alpha1.KprobeAttachInfo{ + { + FunctionName: functionKprobeName, + Offset: uint64(offset), + RetProbe: retprobe, + }, + }, + }, + } + + programs = append(programs, kprobeProgram) + + tracePointProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + Type: bpfmaniov1alpha1.ProgTypeTracepoint, + Tracepoint: &bpfmaniov1alpha1.TracepointProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfTracepointFunctionName, + }, + AttachPoints: []bpfmaniov1alpha1.TracepointAttachInfo{ + { + Name: tracepointName, + }, + }, + }, + } + + programs = append(programs, tracePointProgram) + App := &bpfmaniov1alpha1.BpfApplication{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -68,37 +119,7 @@ func appProgramReconcile(t *testing.T, multiCondition bool) { Path: &bytecodePath, }, }, - Programs: []bpfmaniov1alpha1.BpfApplicationProgram{ - { - Type: bpfmaniov1alpha1.ProgTypeFentry, - Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ - BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ - BpfFunctionName: bpfFentryFunctionName, - }, - FunctionName: functionFentryName, - }, - }, - { - Type: bpfmaniov1alpha1.ProgTypeKprobe, - Kprobe: &bpfmaniov1alpha1.KprobeProgramInfo{ - BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ - BpfFunctionName: bpfKprobeFunctionName, - }, - FunctionName: functionKprobeName, - Offset: uint64(offset), - RetProbe: retprobe, - }, - }, - { - Type: bpfmaniov1alpha1.ProgTypeTracepoint, - Tracepoint: &bpfmaniov1alpha1.TracepointProgramInfo{ - BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ - BpfFunctionName: bpfTracepointFunctionName, - }, - Names: []string{tracepointName}, - }, - }, - }, + Programs: programs, }, } diff --git a/controllers/bpfman-operator/common.go b/controllers/bpfman-operator/common.go index 38061e02d..58554d46f 100644 --- a/controllers/bpfman-operator/common.go +++ b/controllers/bpfman-operator/common.go @@ -120,8 +120,8 @@ func reconcileBpfProgram[T BpfProgOper, TL BpfProgListOper[T]]( for _, node := range nodes.Items { nodeFound := false for _, program := range (*bpfPrograms).GetItems() { - bpfProgramNode := program.GetLabels()[internal.K8sHostLabel] - if node.Name == bpfProgramNode { + bpfProgramState := program.GetLabels()[internal.K8sHostLabel] + if node.Name == bpfProgramState { nodeFound = true break } diff --git a/controllers/bpfman-operator/fentry-program_test.go b/controllers/bpfman-operator/fentry-program_test.go index 335894de0..ac3d8b210 100644 --- a/controllers/bpfman-operator/fentry-program_test.go +++ b/controllers/bpfman-operator/fentry-program_test.go @@ -63,11 +63,11 @@ func fentryProgramReconcile(t *testing.T, multiCondition bool) { }, }, FentryProgramInfo: bpfmaniov1alpha1.FentryProgramInfo{ - BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - FunctionName: functionName, + FentryLoadInfo: bpfmaniov1alpha1.FentryLoadInfo{FunctionName: functionName}, + FentryAttachInfo: bpfmaniov1alpha1.FentryAttachInfo{Attach: true}, }, }, } diff --git a/controllers/bpfman-operator/fexit-program_test.go b/controllers/bpfman-operator/fexit-program_test.go index d2077ece4..3602624c4 100644 --- a/controllers/bpfman-operator/fexit-program_test.go +++ b/controllers/bpfman-operator/fexit-program_test.go @@ -67,7 +67,8 @@ func fexitProgramReconcile(t *testing.T, multiCondition bool) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - FunctionName: functionName, + FexitLoadInfo: bpfmaniov1alpha1.FexitLoadInfo{FunctionName: functionName}, + FexitAttachInfo: bpfmaniov1alpha1.FexitAttachInfo{Attach: true}, }, }, } diff --git a/controllers/bpfman-operator/kprobe-program_test.go b/controllers/bpfman-operator/kprobe-program_test.go index c0864dc58..b6eea6edf 100644 --- a/controllers/bpfman-operator/kprobe-program_test.go +++ b/controllers/bpfman-operator/kprobe-program_test.go @@ -69,9 +69,13 @@ func kprobeProgramReconcile(t *testing.T, multiCondition bool) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - FunctionName: functionName, - Offset: uint64(offset), - RetProbe: retprobe, + AttachPoints: []bpfmaniov1alpha1.KprobeAttachInfo{ + { + FunctionName: functionName, + Offset: uint64(offset), + RetProbe: retprobe, + }, + }, }, }, } diff --git a/controllers/bpfman-operator/tc-ns-program_test.go b/controllers/bpfman-operator/tc-ns-program_test.go index 125a3e7c5..dece53650 100644 --- a/controllers/bpfman-operator/tc-ns-program_test.go +++ b/controllers/bpfman-operator/tc-ns-program_test.go @@ -66,19 +66,23 @@ func TestTcNsProgramReconcile(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &[]string{fakeInt}, - }, - Priority: 0, - Direction: direction, - ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ - bpfmaniov1alpha1.TcProceedOnValue("pipe"), - bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), - }, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "test", + AttachPoints: []bpfmaniov1alpha1.TcNsAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{fakeInt}, + }, + Priority: 0, + Direction: direction, + ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ + bpfmaniov1alpha1.TcProceedOnValue("pipe"), + bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), + }, + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "test", + }, + }, }, }, }, diff --git a/controllers/bpfman-operator/tc-program_test.go b/controllers/bpfman-operator/tc-program_test.go index 8226e95a5..d6d6a3df6 100644 --- a/controllers/bpfman-operator/tc-program_test.go +++ b/controllers/bpfman-operator/tc-program_test.go @@ -66,15 +66,15 @@ func TestTcProgramReconcile(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + AttachPoints: []bpfmaniov1alpha1.TcAttachInfo{{InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ Interfaces: &[]string{fakeInt}, }, - Priority: 0, - Direction: direction, - ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ - bpfmaniov1alpha1.TcProceedOnValue("pipe"), - bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), - }, + Priority: 0, + Direction: direction, + ProceedOn: []bpfmaniov1alpha1.TcProceedOnValue{ + bpfmaniov1alpha1.TcProceedOnValue("pipe"), + bpfmaniov1alpha1.TcProceedOnValue("dispatcher_return"), + }}}, }, }, } diff --git a/controllers/bpfman-operator/tcx-ns-program_test.go b/controllers/bpfman-operator/tcx-ns-program_test.go index 440e3c439..2ae77e5e2 100644 --- a/controllers/bpfman-operator/tcx-ns-program_test.go +++ b/controllers/bpfman-operator/tcx-ns-program_test.go @@ -66,15 +66,19 @@ func TestTcxNsProgramReconcile(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &[]string{fakeInt}, - }, - Priority: 0, - Direction: direction, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "test", + AttachPoints: []bpfmaniov1alpha1.TcxNsAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{fakeInt}, + }, + Priority: 0, + Direction: direction, + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "test", + }, + }, }, }, }, diff --git a/controllers/bpfman-operator/tcx-program_test.go b/controllers/bpfman-operator/tcx-program_test.go index 1a042b320..6d6b1ad37 100644 --- a/controllers/bpfman-operator/tcx-program_test.go +++ b/controllers/bpfman-operator/tcx-program_test.go @@ -66,12 +66,13 @@ func TestTcxProgramReconcile(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &[]string{fakeInt}, - }, - Priority: 0, - Direction: direction, - }, + AttachPoints: []bpfmaniov1alpha1.TcxAttachInfo{{ + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{fakeInt}, + }, + Priority: 0, + Direction: direction, + }}}, }, } diff --git a/controllers/bpfman-operator/tracepoint-program_test.go b/controllers/bpfman-operator/tracepoint-program_test.go index 7b3e2756d..96f3363e7 100644 --- a/controllers/bpfman-operator/tracepoint-program_test.go +++ b/controllers/bpfman-operator/tracepoint-program_test.go @@ -64,7 +64,7 @@ func TestTracepointProgramReconcile(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - Names: []string{tracepointName}, + AttachPoints: []bpfmaniov1alpha1.TracepointAttachInfo{{Name: tracepointName}}, }, }, } diff --git a/controllers/bpfman-operator/uprobe-ns-program_test.go b/controllers/bpfman-operator/uprobe-ns-program_test.go index e99389125..23a2f6eea 100644 --- a/controllers/bpfman-operator/uprobe-ns-program_test.go +++ b/controllers/bpfman-operator/uprobe-ns-program_test.go @@ -66,14 +66,18 @@ func TestUprobeNsProgramReconcile(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - FunctionName: functionName, - Target: target, - Offset: uint64(offset), - RetProbe: retprobe, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "test", + AttachPoints: []bpfmaniov1alpha1.UprobeNsAttachInfo{ + { + FunctionName: functionName, + Target: target, + Offset: uint64(offset), + RetProbe: retprobe, + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "test", + }, + }, }, }, }, diff --git a/controllers/bpfman-operator/uprobe-program_test.go b/controllers/bpfman-operator/uprobe-program_test.go index cb13972e7..09abcee4f 100644 --- a/controllers/bpfman-operator/uprobe-program_test.go +++ b/controllers/bpfman-operator/uprobe-program_test.go @@ -67,10 +67,12 @@ func TestUprobeProgramReconcile(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - FunctionName: functionName, - Target: target, - Offset: uint64(offset), - RetProbe: retprobe, + AttachPoints: []bpfmaniov1alpha1.UprobeAttachInfo{{ + FunctionName: functionName, + Target: target, + Offset: uint64(offset), + RetProbe: retprobe, + }}, }, }, } diff --git a/controllers/bpfman-operator/xdp-ns-program_test.go b/controllers/bpfman-operator/xdp-ns-program_test.go index 3f837cef2..e93a89e48 100644 --- a/controllers/bpfman-operator/xdp-ns-program_test.go +++ b/controllers/bpfman-operator/xdp-ns-program_test.go @@ -66,17 +66,21 @@ func TestXdpNsProgramReconcile(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &[]string{fakeInt}, - }, - Priority: 0, - ProceedOn: []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), - bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return"), - }, - Containers: bpfmaniov1alpha1.ContainerNsSelector{ - Pods: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "test", + AttachPoints: []bpfmaniov1alpha1.XdpNsAttachInfo{ + { + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{fakeInt}, + }, + Priority: 0, + ProceedOn: []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), + bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return"), + }, + Containers: bpfmaniov1alpha1.ContainerNsSelector{ + Pods: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "test", + }, + }, }, }, }, diff --git a/controllers/bpfman-operator/xdp-program_test.go b/controllers/bpfman-operator/xdp-program_test.go index 53aaa5457..5948ae770 100644 --- a/controllers/bpfman-operator/xdp-program_test.go +++ b/controllers/bpfman-operator/xdp-program_test.go @@ -64,13 +64,15 @@ func TestXdpProgramReconcile(t *testing.T) { BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ BpfFunctionName: bpfFunctionName, }, - InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ - Interfaces: &[]string{fakeInt}, - }, - Priority: 0, - ProceedOn: []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), - bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return"), - }, + AttachPoints: []bpfmaniov1alpha1.XdpAttachInfo{{ + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{fakeInt}, + }, + Priority: 0, + ProceedOn: []bpfmaniov1alpha1.XdpProceedOnValue{bpfmaniov1alpha1.XdpProceedOnValue("pass"), + bpfmaniov1alpha1.XdpProceedOnValue("dispatcher_return"), + }, + }}, }, }, } diff --git a/internal/constants.go b/internal/constants.go index 8ccf208e4..f1ba27c26 100644 --- a/internal/constants.go +++ b/internal/constants.go @@ -76,7 +76,8 @@ const ( // object. In the case of a *Program, it will be the name of the *Program // object. In the case of a BpfApplication, it will be the name of the // BpfApplication object. - BpfProgramOwner = "bpfman.io/ownedByProgram" + BpfProgramOwner = "bpfman.io/ownedByProgram" + BpfAppStateOwner = "bpfman.io/ownedByProgram" // AppProgramId is an identifier that is used to identify individual // programs that are part of a given BpfApplication object. *Programs have // an AppProgramId of "". diff --git a/internal/k8s.go b/internal/k8s.go index 174178448..3cbf11993 100644 --- a/internal/k8s.go +++ b/internal/k8s.go @@ -61,8 +61,8 @@ func BpfNsProgramTypePredicate(kind string) predicate.Funcs { } } -// Only reconcile if a bpfprogram has been created for a controller's node. -func BpfProgramNodePredicate(nodeName string) predicate.Funcs { +// Only reconcile if a program has been created for a controller's node. +func BpfNodePredicate(nodeName string) predicate.Funcs { return predicate.Funcs{ GenericFunc: func(e event.GenericEvent) bool { return e.Object.GetLabels()[K8sHostLabel] == nodeName diff --git a/pkg/client/apis/v1alpha1/bpfapplicationstate.go b/pkg/client/apis/v1alpha1/bpfapplicationstate.go new file mode 100644 index 000000000..e8e8384f2 --- /dev/null +++ b/pkg/client/apis/v1alpha1/bpfapplicationstate.go @@ -0,0 +1,68 @@ +/* +Copyright 2023 The bpfman Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// BpfApplicationStateLister helps list BpfApplicationStates. +// All objects returned here must be treated as read-only. +type BpfApplicationStateLister interface { + // List lists all BpfApplicationStates in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.BpfApplicationState, err error) + // Get retrieves the BpfApplicationState from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.BpfApplicationState, error) + BpfApplicationStateListerExpansion +} + +// bpfApplicationStateLister implements the BpfApplicationStateLister interface. +type bpfApplicationStateLister struct { + indexer cache.Indexer +} + +// NewBpfApplicationStateLister returns a new BpfApplicationStateLister. +func NewBpfApplicationStateLister(indexer cache.Indexer) BpfApplicationStateLister { + return &bpfApplicationStateLister{indexer: indexer} +} + +// List lists all BpfApplicationStates in the indexer. +func (s *bpfApplicationStateLister) List(selector labels.Selector) (ret []*v1alpha1.BpfApplicationState, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.BpfApplicationState)) + }) + return ret, err +} + +// Get retrieves the BpfApplicationState from the index for a given name. +func (s *bpfApplicationStateLister) Get(name string) (*v1alpha1.BpfApplicationState, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("bpfapplicationstate"), name) + } + return obj.(*v1alpha1.BpfApplicationState), nil +} diff --git a/pkg/client/apis/v1alpha1/expansion_generated.go b/pkg/client/apis/v1alpha1/expansion_generated.go index 491e889c5..17040799e 100644 --- a/pkg/client/apis/v1alpha1/expansion_generated.go +++ b/pkg/client/apis/v1alpha1/expansion_generated.go @@ -22,6 +22,10 @@ package v1alpha1 // BpfApplicationLister. type BpfApplicationListerExpansion interface{} +// BpfApplicationStateListerExpansion allows custom methods to be added to +// BpfApplicationStateLister. +type BpfApplicationStateListerExpansion interface{} + // BpfNsApplicationListerExpansion allows custom methods to be added to // BpfNsApplicationLister. type BpfNsApplicationListerExpansion interface{} diff --git a/pkg/client/clientset/typed/apis/v1alpha1/apis_client.go b/pkg/client/clientset/typed/apis/v1alpha1/apis_client.go index 7ec7b412d..140883ed5 100644 --- a/pkg/client/clientset/typed/apis/v1alpha1/apis_client.go +++ b/pkg/client/clientset/typed/apis/v1alpha1/apis_client.go @@ -29,6 +29,7 @@ import ( type BpfmanV1alpha1Interface interface { RESTClient() rest.Interface BpfApplicationsGetter + BpfApplicationStatesGetter BpfNsApplicationsGetter BpfNsProgramsGetter BpfProgramsGetter @@ -55,6 +56,10 @@ func (c *BpfmanV1alpha1Client) BpfApplications() BpfApplicationInterface { return newBpfApplications(c) } +func (c *BpfmanV1alpha1Client) BpfApplicationStates() BpfApplicationStateInterface { + return newBpfApplicationStates(c) +} + func (c *BpfmanV1alpha1Client) BpfNsApplications(namespace string) BpfNsApplicationInterface { return newBpfNsApplications(c, namespace) } diff --git a/pkg/client/clientset/typed/apis/v1alpha1/bpfapplicationstate.go b/pkg/client/clientset/typed/apis/v1alpha1/bpfapplicationstate.go new file mode 100644 index 000000000..ab08433eb --- /dev/null +++ b/pkg/client/clientset/typed/apis/v1alpha1/bpfapplicationstate.go @@ -0,0 +1,184 @@ +/* +Copyright 2023 The bpfman Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + scheme "github.com/bpfman/bpfman-operator/pkg/client/clientset/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// BpfApplicationStatesGetter has a method to return a BpfApplicationStateInterface. +// A group's client should implement this interface. +type BpfApplicationStatesGetter interface { + BpfApplicationStates() BpfApplicationStateInterface +} + +// BpfApplicationStateInterface has methods to work with BpfApplicationState resources. +type BpfApplicationStateInterface interface { + Create(ctx context.Context, bpfApplicationState *v1alpha1.BpfApplicationState, opts v1.CreateOptions) (*v1alpha1.BpfApplicationState, error) + Update(ctx context.Context, bpfApplicationState *v1alpha1.BpfApplicationState, opts v1.UpdateOptions) (*v1alpha1.BpfApplicationState, error) + UpdateStatus(ctx context.Context, bpfApplicationState *v1alpha1.BpfApplicationState, opts v1.UpdateOptions) (*v1alpha1.BpfApplicationState, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.BpfApplicationState, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.BpfApplicationStateList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.BpfApplicationState, err error) + BpfApplicationStateExpansion +} + +// bpfApplicationStates implements BpfApplicationStateInterface +type bpfApplicationStates struct { + client rest.Interface +} + +// newBpfApplicationStates returns a BpfApplicationStates +func newBpfApplicationStates(c *BpfmanV1alpha1Client) *bpfApplicationStates { + return &bpfApplicationStates{ + client: c.RESTClient(), + } +} + +// Get takes name of the bpfApplicationState, and returns the corresponding bpfApplicationState object, and an error if there is any. +func (c *bpfApplicationStates) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.BpfApplicationState, err error) { + result = &v1alpha1.BpfApplicationState{} + err = c.client.Get(). + Resource("bpfapplicationstates"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of BpfApplicationStates that match those selectors. +func (c *bpfApplicationStates) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.BpfApplicationStateList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.BpfApplicationStateList{} + err = c.client.Get(). + Resource("bpfapplicationstates"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested bpfApplicationStates. +func (c *bpfApplicationStates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("bpfapplicationstates"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a bpfApplicationState and creates it. Returns the server's representation of the bpfApplicationState, and an error, if there is any. +func (c *bpfApplicationStates) Create(ctx context.Context, bpfApplicationState *v1alpha1.BpfApplicationState, opts v1.CreateOptions) (result *v1alpha1.BpfApplicationState, err error) { + result = &v1alpha1.BpfApplicationState{} + err = c.client.Post(). + Resource("bpfapplicationstates"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(bpfApplicationState). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a bpfApplicationState and updates it. Returns the server's representation of the bpfApplicationState, and an error, if there is any. +func (c *bpfApplicationStates) Update(ctx context.Context, bpfApplicationState *v1alpha1.BpfApplicationState, opts v1.UpdateOptions) (result *v1alpha1.BpfApplicationState, err error) { + result = &v1alpha1.BpfApplicationState{} + err = c.client.Put(). + Resource("bpfapplicationstates"). + Name(bpfApplicationState.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(bpfApplicationState). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *bpfApplicationStates) UpdateStatus(ctx context.Context, bpfApplicationState *v1alpha1.BpfApplicationState, opts v1.UpdateOptions) (result *v1alpha1.BpfApplicationState, err error) { + result = &v1alpha1.BpfApplicationState{} + err = c.client.Put(). + Resource("bpfapplicationstates"). + Name(bpfApplicationState.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(bpfApplicationState). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the bpfApplicationState and deletes it. Returns an error if one occurs. +func (c *bpfApplicationStates) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("bpfapplicationstates"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *bpfApplicationStates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("bpfapplicationstates"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched bpfApplicationState. +func (c *bpfApplicationStates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.BpfApplicationState, err error) { + result = &v1alpha1.BpfApplicationState{} + err = c.client.Patch(pt). + Resource("bpfapplicationstates"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_apis_client.go b/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_apis_client.go index 9e7d2f76c..9f6914c20 100644 --- a/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_apis_client.go +++ b/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_apis_client.go @@ -32,6 +32,10 @@ func (c *FakeBpfmanV1alpha1) BpfApplications() v1alpha1.BpfApplicationInterface return &FakeBpfApplications{c} } +func (c *FakeBpfmanV1alpha1) BpfApplicationStates() v1alpha1.BpfApplicationStateInterface { + return &FakeBpfApplicationStates{c} +} + func (c *FakeBpfmanV1alpha1) BpfNsApplications(namespace string) v1alpha1.BpfNsApplicationInterface { return &FakeBpfNsApplications{c, namespace} } diff --git a/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_bpfapplicationstate.go b/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_bpfapplicationstate.go new file mode 100644 index 000000000..1155746a9 --- /dev/null +++ b/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_bpfapplicationstate.go @@ -0,0 +1,132 @@ +/* +Copyright 2023 The bpfman Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeBpfApplicationStates implements BpfApplicationStateInterface +type FakeBpfApplicationStates struct { + Fake *FakeBpfmanV1alpha1 +} + +var bpfapplicationstatesResource = v1alpha1.SchemeGroupVersion.WithResource("bpfapplicationstates") + +var bpfapplicationstatesKind = v1alpha1.SchemeGroupVersion.WithKind("BpfApplicationState") + +// Get takes name of the bpfApplicationState, and returns the corresponding bpfApplicationState object, and an error if there is any. +func (c *FakeBpfApplicationStates) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.BpfApplicationState, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(bpfapplicationstatesResource, name), &v1alpha1.BpfApplicationState{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BpfApplicationState), err +} + +// List takes label and field selectors, and returns the list of BpfApplicationStates that match those selectors. +func (c *FakeBpfApplicationStates) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.BpfApplicationStateList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(bpfapplicationstatesResource, bpfapplicationstatesKind, opts), &v1alpha1.BpfApplicationStateList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.BpfApplicationStateList{ListMeta: obj.(*v1alpha1.BpfApplicationStateList).ListMeta} + for _, item := range obj.(*v1alpha1.BpfApplicationStateList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested bpfApplicationStates. +func (c *FakeBpfApplicationStates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(bpfapplicationstatesResource, opts)) +} + +// Create takes the representation of a bpfApplicationState and creates it. Returns the server's representation of the bpfApplicationState, and an error, if there is any. +func (c *FakeBpfApplicationStates) Create(ctx context.Context, bpfApplicationState *v1alpha1.BpfApplicationState, opts v1.CreateOptions) (result *v1alpha1.BpfApplicationState, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(bpfapplicationstatesResource, bpfApplicationState), &v1alpha1.BpfApplicationState{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BpfApplicationState), err +} + +// Update takes the representation of a bpfApplicationState and updates it. Returns the server's representation of the bpfApplicationState, and an error, if there is any. +func (c *FakeBpfApplicationStates) Update(ctx context.Context, bpfApplicationState *v1alpha1.BpfApplicationState, opts v1.UpdateOptions) (result *v1alpha1.BpfApplicationState, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(bpfapplicationstatesResource, bpfApplicationState), &v1alpha1.BpfApplicationState{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BpfApplicationState), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeBpfApplicationStates) UpdateStatus(ctx context.Context, bpfApplicationState *v1alpha1.BpfApplicationState, opts v1.UpdateOptions) (*v1alpha1.BpfApplicationState, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(bpfapplicationstatesResource, "status", bpfApplicationState), &v1alpha1.BpfApplicationState{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BpfApplicationState), err +} + +// Delete takes name of the bpfApplicationState and deletes it. Returns an error if one occurs. +func (c *FakeBpfApplicationStates) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(bpfapplicationstatesResource, name, opts), &v1alpha1.BpfApplicationState{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeBpfApplicationStates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(bpfapplicationstatesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.BpfApplicationStateList{}) + return err +} + +// Patch applies the patch and returns the patched bpfApplicationState. +func (c *FakeBpfApplicationStates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.BpfApplicationState, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(bpfapplicationstatesResource, name, pt, data, subresources...), &v1alpha1.BpfApplicationState{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BpfApplicationState), err +} diff --git a/pkg/client/clientset/typed/apis/v1alpha1/generated_expansion.go b/pkg/client/clientset/typed/apis/v1alpha1/generated_expansion.go index 3b956a1a6..212285d6c 100644 --- a/pkg/client/clientset/typed/apis/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/typed/apis/v1alpha1/generated_expansion.go @@ -20,6 +20,8 @@ package v1alpha1 type BpfApplicationExpansion interface{} +type BpfApplicationStateExpansion interface{} + type BpfNsApplicationExpansion interface{} type BpfNsProgramExpansion interface{} diff --git a/pkg/client/externalversions/apis/v1alpha1/bpfapplicationstate.go b/pkg/client/externalversions/apis/v1alpha1/bpfapplicationstate.go new file mode 100644 index 000000000..f1f141ec4 --- /dev/null +++ b/pkg/client/externalversions/apis/v1alpha1/bpfapplicationstate.go @@ -0,0 +1,89 @@ +/* +Copyright 2023 The bpfman Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + apisv1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + v1alpha1 "github.com/bpfman/bpfman-operator/pkg/client/apis/v1alpha1" + clientset "github.com/bpfman/bpfman-operator/pkg/client/clientset" + internalinterfaces "github.com/bpfman/bpfman-operator/pkg/client/externalversions/internalinterfaces" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// BpfApplicationStateInformer provides access to a shared informer and lister for +// BpfApplicationStates. +type BpfApplicationStateInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.BpfApplicationStateLister +} + +type bpfApplicationStateInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewBpfApplicationStateInformer constructs a new informer for BpfApplicationState type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewBpfApplicationStateInformer(client clientset.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredBpfApplicationStateInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredBpfApplicationStateInformer constructs a new informer for BpfApplicationState type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredBpfApplicationStateInformer(client clientset.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.BpfmanV1alpha1().BpfApplicationStates().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.BpfmanV1alpha1().BpfApplicationStates().Watch(context.TODO(), options) + }, + }, + &apisv1alpha1.BpfApplicationState{}, + resyncPeriod, + indexers, + ) +} + +func (f *bpfApplicationStateInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredBpfApplicationStateInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *bpfApplicationStateInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisv1alpha1.BpfApplicationState{}, f.defaultInformer) +} + +func (f *bpfApplicationStateInformer) Lister() v1alpha1.BpfApplicationStateLister { + return v1alpha1.NewBpfApplicationStateLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/externalversions/apis/v1alpha1/interface.go b/pkg/client/externalversions/apis/v1alpha1/interface.go index 7ca2dcbec..b53d7323f 100644 --- a/pkg/client/externalversions/apis/v1alpha1/interface.go +++ b/pkg/client/externalversions/apis/v1alpha1/interface.go @@ -26,6 +26,8 @@ import ( type Interface interface { // BpfApplications returns a BpfApplicationInformer. BpfApplications() BpfApplicationInformer + // BpfApplicationStates returns a BpfApplicationStateInformer. + BpfApplicationStates() BpfApplicationStateInformer // BpfNsApplications returns a BpfNsApplicationInformer. BpfNsApplications() BpfNsApplicationInformer // BpfNsPrograms returns a BpfNsProgramInformer. @@ -74,6 +76,11 @@ func (v *version) BpfApplications() BpfApplicationInformer { return &bpfApplicationInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } +// BpfApplicationStates returns a BpfApplicationStateInformer. +func (v *version) BpfApplicationStates() BpfApplicationStateInformer { + return &bpfApplicationStateInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + // BpfNsApplications returns a BpfNsApplicationInformer. func (v *version) BpfNsApplications() BpfNsApplicationInformer { return &bpfNsApplicationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/externalversions/generic.go b/pkg/client/externalversions/generic.go index 2d084ef57..efb05511c 100644 --- a/pkg/client/externalversions/generic.go +++ b/pkg/client/externalversions/generic.go @@ -55,6 +55,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource // Group=bpfman.io, Version=v1alpha1 case v1alpha1.SchemeGroupVersion.WithResource("bpfapplications"): return &genericInformer{resource: resource.GroupResource(), informer: f.Bpfman().V1alpha1().BpfApplications().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("bpfapplicationstates"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Bpfman().V1alpha1().BpfApplicationStates().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("bpfnsapplications"): return &genericInformer{resource: resource.GroupResource(), informer: f.Bpfman().V1alpha1().BpfNsApplications().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("bpfnsprograms"): diff --git a/pkg/helpers/helpers.go b/pkg/helpers/helpers.go index 62bfe22cf..f5e8d8deb 100644 --- a/pkg/helpers/helpers.go +++ b/pkg/helpers/helpers.go @@ -326,3 +326,23 @@ func IsBpfProgramConditionFailure(conditions *[]metav1.Condition) bool { return false } + +func IsBpfAppStateConditionFailure(conditions *[]metav1.Condition) bool { + if conditions == nil || *conditions == nil || len(*conditions) == 0 { + return true + } + + numConditions := len(*conditions) + + if numConditions > 1 { + // We should only ever have one condition so log a message, but + // still look at (*conditions)[0]. + log.Info("more than one BpfProgramCondition", "numConditions", numConditions) + } + + if (*conditions)[0].Type == string(bpfmaniov1alpha1.ProgramReconcileSuccess) { + return false + } else { + return true + } +}