From 9e5cb54d30d839e1cec999663b05b4581ed7c06b Mon Sep 17 00:00:00 2001 From: Andre Fredette Date: Mon, 9 Dec 2024 18:44:14 -0500 Subject: [PATCH 1/3] Initial support for Load/Attach Split Includes support for Cluster-Scoped XDP, TXC, and Fentry Programs This commit introduces the foundation for the load/attach split, including: - Updates to the `BpfApplication` CRD to support a separate list of optional attach points for programs. This allows programs to be loaded before attachments are made and enables dynamic attachment updates. - An initial version of the `BpfApplicationState` CRD to manage per-node information for a single `BpfApplication`. - Proof of concept and initial implementation for cluster-scoped XDP, TCX, and Fentry programs, with working unit tests and samples. See TODO.md for more info. Signed-off-by: Andre Fredette --- Makefile | 4 +- PROJECT | 7 + TODO.md | 51 + apis/v1alpha1/bpfApplicationState_types.go | 173 +++ apis/v1alpha1/bpfApplication_types.go | 19 +- apis/v1alpha1/bpfNsApplication_types.go | 2 +- apis/v1alpha1/fentryProgram_types.go | 40 +- apis/v1alpha1/fexitProgram_types.go | 24 +- apis/v1alpha1/kprobeProgram_types.go | 18 +- apis/v1alpha1/shared_types.go | 91 +- apis/v1alpha1/tcNsProgram_types.go | 10 +- apis/v1alpha1/tcProgram_types.go | 58 +- apis/v1alpha1/tcxNsProgram_types.go | 11 +- apis/v1alpha1/tcxProgram_types.go | 52 +- apis/v1alpha1/tracepointProgram_types.go | 20 +- apis/v1alpha1/uprobeNsProgram_types.go | 10 +- apis/v1alpha1/uprobeProgram_types.go | 16 +- apis/v1alpha1/xdpNsProgram_types.go | 7 + apis/v1alpha1/xdpProgram_types.go | 47 +- apis/v1alpha1/zz_generated.deepcopy.go | 720 +++++++-- apis/v1alpha1/zz_generated.register.go | 2 + ...c.authorization.k8s.io_v1_clusterrole.yaml | 26 + .../manifests/bpfman-config_v1_configmap.yaml | 2 +- ...bpfman-operator.clusterserviceversion.yaml | 119 +- .../manifests/bpfman.io_bpfapplications.yaml | 1381 ++++++++++------- .../bpfman.io_bpfapplicationstates.yaml | 413 +++++ .../bpfman.io_bpfnsapplications.yaml | 1165 +++++++------- .../manifests/bpfman.io_fentryprograms.yaml | 73 +- bundle/manifests/bpfman.io_fexitprograms.yaml | 72 +- .../manifests/bpfman.io_kprobeprograms.yaml | 106 +- bundle/manifests/bpfman.io_tcnsprograms.yaml | 318 ++-- bundle/manifests/bpfman.io_tcprograms.yaml | 326 ++-- bundle/manifests/bpfman.io_tcxnsprograms.yaml | 273 ++-- bundle/manifests/bpfman.io_tcxprograms.yaml | 288 ++-- .../bpfman.io_tracepointprograms.yaml | 85 +- .../manifests/bpfman.io_uprobensprograms.yaml | 252 +-- .../manifests/bpfman.io_uprobeprograms.yaml | 258 +-- bundle/manifests/bpfman.io_xdpnsprograms.yaml | 287 ++-- bundle/manifests/bpfman.io_xdpprograms.yaml | 296 ++-- cmd/bpfman-agent/main.go | 243 +-- cmd/bpfman-operator/main.go | 220 +-- config/bpfman-deployment/config.yaml | 2 +- .../crd/bases/bpfman.io_bpfapplications.yaml | 1381 ++++++++++------- .../bases/bpfman.io_bpfapplicationstates.yaml | 407 +++++ .../bases/bpfman.io_bpfnsapplications.yaml | 1165 +++++++------- .../crd/bases/bpfman.io_fentryprograms.yaml | 73 +- config/crd/bases/bpfman.io_fexitprograms.yaml | 72 +- .../crd/bases/bpfman.io_kprobeprograms.yaml | 106 +- config/crd/bases/bpfman.io_tcnsprograms.yaml | 318 ++-- config/crd/bases/bpfman.io_tcprograms.yaml | 326 ++-- config/crd/bases/bpfman.io_tcxnsprograms.yaml | 273 ++-- config/crd/bases/bpfman.io_tcxprograms.yaml | 288 ++-- .../bases/bpfman.io_tracepointprograms.yaml | 85 +- .../crd/bases/bpfman.io_uprobensprograms.yaml | 252 +-- .../crd/bases/bpfman.io_uprobeprograms.yaml | 258 +-- config/crd/bases/bpfman.io_xdpnsprograms.yaml | 287 ++-- config/crd/bases/bpfman.io_xdpprograms.yaml | 296 ++-- config/crd/kustomization.yaml | 1 + config/openshift/patch.yaml | 2 +- config/rbac/bpfman-agent/role.yaml | 26 + config/rbac/bpfman-operator/role.yaml | 8 + .../bpfman.io_v1alpha1_bpfapplication.yaml | 100 +- ...man.io_v1alpha1_fentry_bpfapplication.yaml | 19 + controllers/app-agent/application-program.go | 505 ++++++ .../app-agent/application-program_test.go | 235 +++ controllers/app-agent/common.go | 531 +++++++ controllers/app-agent/containers.go | 252 +++ controllers/app-agent/fentry-program.go | 256 +++ controllers/app-agent/internal/auth.go | 144 ++ controllers/app-agent/internal/bpfman-core.go | 206 +++ controllers/app-agent/internal/cmp.go | 183 +++ controllers/app-agent/internal/iface.go | 63 + .../internal/test-utils/fake_bpfman_client.go | 120 ++ controllers/app-agent/tcx-program.go | 311 ++++ controllers/app-agent/xdp-program.go | 332 ++++ .../app-operator/application-program_test.go | 264 ++++ .../app-operator/application-programs.go | 123 ++ controllers/app-operator/common.go | 244 +++ controllers/app-operator/common_cluster.go | 83 + controllers/app-operator/configmap.go | 350 +++++ controllers/app-operator/configmap_test.go | 256 +++ .../bpfman-agent/application-ns-program.go | 14 +- .../application-ns-program_test.go | 46 +- .../bpfman-agent/application-program.go | 16 +- .../bpfman-agent/application-program_test.go | 52 +- controllers/bpfman-agent/common.go | 2 +- controllers/bpfman-agent/fentry-program.go | 2 +- .../bpfman-agent/fentry-program_test.go | 3 +- controllers/bpfman-agent/fexit-program.go | 2 +- .../bpfman-agent/fexit-program_test.go | 3 +- controllers/bpfman-agent/kprobe-program.go | 10 +- .../bpfman-agent/kprobe-program_test.go | 10 +- controllers/bpfman-agent/tc-ns-program.go | 18 +- .../bpfman-agent/tc-ns-program_test.go | 65 +- controllers/bpfman-agent/tc-program.go | 24 +- controllers/bpfman-agent/tc-program_test.go | 41 +- controllers/bpfman-agent/tcx-ns-program.go | 16 +- .../bpfman-agent/tcx-ns-program_test.go | 52 +- controllers/bpfman-agent/tcx-program.go | 22 +- controllers/bpfman-agent/tcx-program_test.go | 30 +- .../bpfman-agent/tracepoint-program.go | 19 +- .../bpfman-agent/tracepoint-program_test.go | 2 +- controllers/bpfman-agent/uprobe-ns-program.go | 18 +- .../bpfman-agent/uprobe-ns-program_test.go | 20 +- controllers/bpfman-agent/uprobe-program.go | 25 +- .../bpfman-agent/uprobe-program_test.go | 29 +- controllers/bpfman-agent/xdp-ns-program.go | 12 +- .../bpfman-agent/xdp-ns-program_test.go | 26 +- controllers/bpfman-agent/xdp-program.go | 16 +- controllers/bpfman-agent/xdp-program_test.go | 16 +- .../application-ns-program_test.go | 72 +- .../application-program_test.go | 77 +- controllers/bpfman-operator/common.go | 4 +- .../bpfman-operator/fentry-program_test.go | 4 +- .../bpfman-operator/fexit-program_test.go | 3 +- .../bpfman-operator/kprobe-program_test.go | 10 +- .../bpfman-operator/tc-ns-program_test.go | 30 +- .../bpfman-operator/tc-program_test.go | 14 +- .../bpfman-operator/tcx-ns-program_test.go | 22 +- .../bpfman-operator/tcx-program_test.go | 13 +- .../tracepoint-program_test.go | 2 +- .../bpfman-operator/uprobe-ns-program_test.go | 20 +- .../bpfman-operator/uprobe-program_test.go | 10 +- .../bpfman-operator/xdp-ns-program_test.go | 26 +- .../bpfman-operator/xdp-program_test.go | 16 +- internal/constants.go | 3 +- internal/k8s.go | 4 +- .../apis/v1alpha1/bpfapplicationstate.go | 68 + .../apis/v1alpha1/expansion_generated.go | 4 + .../typed/apis/v1alpha1/apis_client.go | 5 + .../apis/v1alpha1/bpfapplicationstate.go | 184 +++ .../apis/v1alpha1/fake/fake_apis_client.go | 4 + .../v1alpha1/fake/fake_bpfapplicationstate.go | 132 ++ .../apis/v1alpha1/generated_expansion.go | 2 + .../apis/v1alpha1/bpfapplicationstate.go | 89 ++ .../apis/v1alpha1/interface.go | 7 + pkg/client/externalversions/generic.go | 2 + pkg/helpers/helpers.go | 20 + 138 files changed, 14213 insertions(+), 5033 deletions(-) create mode 100644 TODO.md create mode 100644 apis/v1alpha1/bpfApplicationState_types.go create mode 100644 bundle/manifests/bpfman.io_bpfapplicationstates.yaml create mode 100644 config/crd/bases/bpfman.io_bpfapplicationstates.yaml create mode 100644 config/samples/bpfman.io_v1alpha1_fentry_bpfapplication.yaml create mode 100644 controllers/app-agent/application-program.go create mode 100644 controllers/app-agent/application-program_test.go create mode 100644 controllers/app-agent/common.go create mode 100644 controllers/app-agent/containers.go create mode 100644 controllers/app-agent/fentry-program.go create mode 100644 controllers/app-agent/internal/auth.go create mode 100644 controllers/app-agent/internal/bpfman-core.go create mode 100644 controllers/app-agent/internal/cmp.go create mode 100644 controllers/app-agent/internal/iface.go create mode 100644 controllers/app-agent/internal/test-utils/fake_bpfman_client.go create mode 100644 controllers/app-agent/tcx-program.go create mode 100644 controllers/app-agent/xdp-program.go create mode 100644 controllers/app-operator/application-program_test.go create mode 100644 controllers/app-operator/application-programs.go create mode 100644 controllers/app-operator/common.go create mode 100644 controllers/app-operator/common_cluster.go create mode 100644 controllers/app-operator/configmap.go create mode 100644 controllers/app-operator/configmap_test.go create mode 100644 pkg/client/apis/v1alpha1/bpfapplicationstate.go create mode 100644 pkg/client/clientset/typed/apis/v1alpha1/bpfapplicationstate.go create mode 100644 pkg/client/clientset/typed/apis/v1alpha1/fake/fake_bpfapplicationstate.go create mode 100644 pkg/client/externalversions/apis/v1alpha1/bpfapplicationstate.go 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..ce2551825 --- /dev/null +++ b/TODO.md @@ -0,0 +1,51 @@ +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). + +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: + +- 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..3dedaa9c6 --- /dev/null +++ b/apis/v1alpha1/bpfApplicationState_types.go @@ -0,0 +1,173 @@ +/* +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 { + // 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"` + + // 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 { + // 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 map[string]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=".metadata.labels['kubernetes.io/hostname']" +// +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..a7830abdb 100644 --- a/apis/v1alpha1/bpfApplication_types.go +++ b/apis/v1alpha1/bpfApplication_types.go @@ -129,16 +129,11 @@ type BpfApplicationProgram struct { 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 []BpfApplicationProgram `json:"programs,omitempty"` -} - -// BpfApplicationStatus defines the observed state of BpfApplication -type BpfApplicationStatus struct { - BpfProgramStatusCommon `json:",inline"` + // 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. The list is + // implemented as a map from the bpf function name to BpfApplicationProgram. + Programs map[string]BpfApplicationProgram `json:"programs,omitempty"` } // +genclient @@ -155,8 +150,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..c4c7e3fb4 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"` } -// FentryProgramStatus defines the observed state of FentryProgram -type FentryProgramStatus struct { - BpfProgramStatusCommon `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"` +} + +type FentryAttachInfo struct { + // Whether the bpf program should be attached to the function. + Attach bool `json:"attach"` } // +kubebuilder:object:root=true @@ -68,3 +77,18 @@ type FentryProgramList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []FentryProgram `json:"items"` } + +type FentryProgramInfoState struct { + // The list of points to which the program should be attached. For Fentry + // programs, there will be at most one attach point, but it's being + // maintained as a list for consistency with most of the other program + // types. + // +optional + AttachPoints []FentryAttachInfoState `json:"attach_points"` +} + +type FentryAttachInfoState struct { + AttachInfoCommon `json:",inline"` + // FunctionName is the name of the function to attach the Fentry program to. + FunctionName string `json:"function_name"` +} 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..a3ca66d3c 100644 --- a/apis/v1alpha1/shared_types.go +++ b/apis/v1alpha1/shared_types.go @@ -69,16 +69,20 @@ type ContainerNsSelector struct { // BpfProgramCommon defines the common attributes for all BPF programs type BpfProgramCommon struct { + // ANF-TODO: BpfProgramCommon is deprecated and will be removed. + // MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + // key for the Programs list in the BpfApplicationSpec. Do not use in new + // load/attach split code. // 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 + // 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 +102,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 +126,22 @@ 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"` +} + // PullPolicy describes a policy for if/when to pull a container image // +kubebuilder:validation:Enum=Always;Never;IfNotPresent type PullPolicy string @@ -293,6 +324,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 +416,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..3852ffc87 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"` @@ -83,7 +91,7 @@ type XdpProgramInfo struct { // XdpProgramStatus defines the observed state of XdpProgram type XdpProgramStatus struct { - BpfProgramStatusCommon `json:",inline"` + BpfAppStatus `json:",inline"` } // +kubebuilder:object:root=true @@ -93,3 +101,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..aaa429ab5 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 @@ -182,15 +229,50 @@ 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 + if in.ProgramId != nil { + in, out := &in.ProgramId, &out.ProgramId + *out = new(uint32) + **out = **in + } + if in.XDP != nil { + in, out := &in.XDP, &out.XDP + *out = new(XdpProgramInfoState) + (*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 in.BpfAppCommon.DeepCopyInto(&out.BpfAppCommon) if in.Programs != nil { in, out := &in.Programs, &out.Programs - *out = make([]BpfApplicationProgram, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) + *out = make(map[string]BpfApplicationProgram, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() } } } @@ -206,17 +288,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(map[string]BpfApplicationProgramState, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// 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 +579,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. @@ -514,28 +661,6 @@ func (in *BpfProgramStatus) DeepCopy() *BpfProgramStatus { 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) { - *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 BpfProgramStatusCommon. -func (in *BpfProgramStatusCommon) DeepCopy() *BpfProgramStatusCommon { - if in == nil { - return nil - } - out := new(BpfProgramStatusCommon) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BytecodeImage) DeepCopyInto(out *BytecodeImage) { *out = *in @@ -631,6 +756,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 +833,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 +847,28 @@ 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 + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]FentryAttachInfoState, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// 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 +919,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 +979,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 +1042,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 +1086,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 +1132,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 +1199,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.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([]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 TcAttachInfo. +func (in *TcAttachInfo) DeepCopy() *TcAttachInfo { if in == nil { return nil } - out := new(KprobeProgramStatus) + 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.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 TcNsAttachInfo. +func (in *TcNsAttachInfo) DeepCopy() *TcNsAttachInfo { + if in == nil { + return nil + } + out := new(TcNsAttachInfo) in.DeepCopyInto(out) return out } @@ -1030,12 +1308,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 +1407,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 +1426,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 +1498,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 +1587,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 +1686,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 +1705,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 +1777,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 +1822,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 +1889,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 +1955,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 +2054,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 +2123,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.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 XdpAttachInfo. +func (in *XdpAttachInfo) DeepCopy() *XdpAttachInfo { + if in == nil { + return nil + } + 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.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([]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 XdpNsAttachInfo. +func (in *XdpNsAttachInfo) DeepCopy() *XdpNsAttachInfo { if in == nil { return nil } - out := new(UprobeProgramStatus) + out := new(XdpNsAttachInfo) in.DeepCopyInto(out) return out } @@ -1775,12 +2227,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 +2326,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 +2345,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 +2419,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..90fc8c56e 100644 --- a/bundle/manifests/bpfman-operator.clusterserviceversion.yaml +++ b/bundle/manifests/bpfman-operator.clusterserviceversion.yaml @@ -20,79 +20,55 @@ metadata: } }, "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" - }, - { + "programs": { + "tcx_stats": { "tcx": { - "bpffunctionname": "tcx_stats", - "direction": "ingress", - "interfaceselector": { - "primarynodeinterface": true - }, - "priority": 500 + "attach_points": [ + { + "direction": "ingress", + "interfaceselector": { + "primarynodeinterface": true + }, + "priority": 500 + } + ], + "bpffunctionname": "tcx_stats" }, "type": "TCX" }, - { - "type": "Uprobe", - "uprobe": { - "bpffunctionname": "uprobe_counter", - "containers": { - "containernames": [ - "bpfman", - "bpfman-agent" - ], - "namespace": "bpfman", - "pods": { - "matchLabels": { - "name": "bpfman-daemon" - } - } - }, - "func_name": "malloc", - "retprobe": false, - "target": "libc" - } - }, - { + "xdp_stats": { "type": "XDP", "xdp": { - "bpffunctionname": "xdp_stats", - "interfaceselector": { - "primarynodeinterface": true - }, - "priority": 55 + "attach_points": [ + { + "interfaceselector": { + "primarynodeinterface": true + }, + "priority": 55 + }, + { + "containers": { + "containernames": [ + "bpfman", + "bpfman-agent" + ], + "namespace": "bpfman", + "pods": { + "matchLabels": { + "name": "bpfman-daemon" + } + } + }, + "interfaceselector": { + "primarynodeinterface": true + }, + "priority": 100 + } + ], + "bpffunctionname": "xdp_stats" } } - ] + } } }, { @@ -619,7 +595,7 @@ metadata: capabilities: Basic Install categories: OpenShift Optional containerImage: quay.io/bpfman/bpfman-operator:latest - createdAt: "2025-01-08T17:26:28Z" + createdAt: "2025-01-24T22:01:22Z" features.operators.openshift.io/cnf: "false" features.operators.openshift.io/cni: "false" features.operators.openshift.io/csi: "true" @@ -669,6 +645,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 +1084,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..1f98fb808 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 @@ -154,11 +204,7 @@ spec: type: object 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. - items: + additionalProperties: description: BpfApplicationProgram defines the desired state of BpfApplication properties: @@ -166,17 +212,26 @@ spec: 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. 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 + 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. @@ -225,24 +280,32 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. 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 + 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. @@ -291,24 +354,54 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. 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 + 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. @@ -356,37 +449,53 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. 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 + 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. @@ -434,128 +543,164 @@ 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 tc: description: tc defines the desired state of the application's TcPrograms. 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 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 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 + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -603,150 +748,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 - - 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: |- - 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 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 + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -794,33 +930,40 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. 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 + 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. @@ -868,16 +1011,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,88 +1032,124 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -1026,117 +1197,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 - - 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -1184,129 +1369,147 @@ 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: |- + 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 - 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 + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + required: + - interfaceselector + - priority + type: object + type: array + bpffunctionname: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + oldmapownerselector: + description: |- + 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. @@ -1354,34 +1557,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 - items: - enum: - - aborted - - drop - - pass - - tx - - redirect - - dispatcher_return - type: string - maxItems: 6 - type: array required: - bpffunctionname - - interfaceselector - - priority type: object type: object x-kubernetes-validations: @@ -1425,19 +1602,25 @@ spec: and forbidden otherwise rule: 'has(self.type) && self.type == ''Tracepoint'' ? has(self.tracepoint) : !has(self.tracepoint)' - minItems: 1 - type: array + description: |- + 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. The list is + implemented as a map from the bpf function name to BpfApplicationProgram. + type: object 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..817ba9dfc --- /dev/null +++ b/bundle/manifests/bpfman.io_bpfapplicationstates.yaml @@ -0,0 +1,413 @@ +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 + programs: + additionalProperties: + 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: + fentry: + description: fentry defines the desired state of the application's + FentryPrograms. + properties: + attach_points: + description: |- + The list of points to which the program should be attached. For Fentry + programs, there will be at most one attach point, but it's being + maintained as a list for consistency with most of the other program + types. + 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 + function_name: + description: FunctionName is the name of the function + to attach the Fentry program to. + 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: + - attachid + - attachstatus + - function_name + - should_attach + - uuid + type: object + type: array + type: object + 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 + 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: + - 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)' + 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. + type: object + 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 + - 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..45ec0d69c 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,103 +216,153 @@ 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 + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -310,146 +410,138 @@ 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 + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -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,84 +605,121 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -651,114 +767,128 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -806,125 +936,146 @@ 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 + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + oldmapownerselector: + description: |- + 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. @@ -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..b26a5d35c 100644 --- a/bundle/manifests/bpfman.io_fentryprograms.yaml +++ b/bundle/manifests/bpfman.io_fentryprograms.yaml @@ -53,8 +53,15 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -103,8 +110,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 +223,72 @@ spec: type: object type: object x-kubernetes-map-type: atomic + oldmapownerselector: + description: |- + 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..b71ec7519 100644 --- a/bundle/manifests/bpfman.io_fexitprograms.yaml +++ b/bundle/manifests/bpfman.io_fexitprograms.yaml @@ -53,8 +53,14 @@ spec: spec: description: FexitProgramSpec defines the desired state of FexitProgram properties: + attach: + type: boolean bpffunctionname: description: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -103,8 +109,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 +222,72 @@ spec: type: object type: object x-kubernetes-map-type: atomic + oldmapownerselector: + description: |- + 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..f5714de0d 100644 --- a/bundle/manifests/bpfman.io_kprobeprograms.yaml +++ b/bundle/manifests/bpfman.io_kprobeprograms.yaml @@ -61,8 +61,40 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -111,9 +143,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 +252,70 @@ 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 + 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..28b08fd72 100644 --- a/bundle/manifests/bpfman.io_tcnsprograms.yaml +++ b/bundle/manifests/bpfman.io_tcnsprograms.yaml @@ -65,8 +65,146 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -115,77 +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. - 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 +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 @@ -312,54 +362,70 @@ 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 + 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..105d4cdfa 100644 --- a/bundle/manifests/bpfman.io_tcprograms.yaml +++ b/bundle/manifests/bpfman.io_tcprograms.yaml @@ -65,8 +65,150 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -115,82 +257,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 +267,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 +366,70 @@ 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 + 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..62a4fbaa6 100644 --- a/bundle/manifests/bpfman.io_tcxnsprograms.yaml +++ b/bundle/manifests/bpfman.io_tcxnsprograms.yaml @@ -65,8 +65,124 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -115,77 +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 - 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 +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 @@ -312,31 +340,70 @@ 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 + 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..43f88689a 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,8 +65,127 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -115,82 +234,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 +244,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 +343,70 @@ 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 + 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..4d70631f0 100644 --- a/bundle/manifests/bpfman.io_tracepointprograms.yaml +++ b/bundle/manifests/bpfman.io_tracepointprograms.yaml @@ -53,8 +53,27 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -163,13 +182,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 +231,70 @@ spec: type: object type: object x-kubernetes-map-type: atomic + oldmapownerselector: + description: |- + 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..769b4c51f 100644 --- a/bundle/manifests/bpfman.io_uprobensprograms.yaml +++ b/bundle/manifests/bpfman.io_uprobensprograms.yaml @@ -69,8 +69,114 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -119,76 +225,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 +334,70 @@ 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 + 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..b509ebcd4 100644 --- a/bundle/manifests/bpfman.io_uprobeprograms.yaml +++ b/bundle/manifests/bpfman.io_uprobeprograms.yaml @@ -69,8 +69,117 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -119,80 +228,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 +337,70 @@ 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 + 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..09fa8a530 100644 --- a/bundle/manifests/bpfman.io_xdpnsprograms.yaml +++ b/bundle/manifests/bpfman.io_xdpnsprograms.yaml @@ -61,8 +61,132 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -111,69 +235,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 +245,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 +344,69 @@ 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 + oldmapownerselector: 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 + 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..b20202509 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,8 +65,133 @@ 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 + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + required: + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -111,74 +240,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 +250,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 +349,70 @@ 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 + 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..9890105f3 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 @@ -154,11 +204,7 @@ spec: type: object 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. - items: + additionalProperties: description: BpfApplicationProgram defines the desired state of BpfApplication properties: @@ -166,17 +212,26 @@ spec: 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. 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 + 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. @@ -225,24 +280,32 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. 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 + 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. @@ -291,24 +354,54 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. 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 + 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. @@ -356,37 +449,53 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. 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 + 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. @@ -434,128 +543,164 @@ 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 tc: description: tc defines the desired state of the application's TcPrograms. 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 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 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 + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -603,150 +748,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 - - 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: |- - 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 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 + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -794,33 +930,40 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. 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 + 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. @@ -868,16 +1011,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,88 +1032,124 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -1026,117 +1197,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 - - 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -1184,129 +1369,147 @@ 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: |- + 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 - 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 + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + required: + - interfaceselector + - priority + type: object + type: array + bpffunctionname: description: |- - MapOwnerSelector is used to select the loaded eBPF program this eBPF program + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + oldmapownerselector: + description: |- + 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. @@ -1354,34 +1557,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 - items: - enum: - - aborted - - drop - - pass - - tx - - redirect - - dispatcher_return - type: string - maxItems: 6 - type: array required: - bpffunctionname - - interfaceselector - - priority type: object type: object x-kubernetes-validations: @@ -1425,19 +1602,25 @@ spec: and forbidden otherwise rule: 'has(self.type) && self.type == ''Tracepoint'' ? has(self.tracepoint) : !has(self.tracepoint)' - minItems: 1 - type: array + description: |- + 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. The list is + implemented as a map from the bpf function name to BpfApplicationProgram. + type: object 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..bc0f24b0f --- /dev/null +++ b/config/crd/bases/bpfman.io_bpfapplicationstates.yaml @@ -0,0 +1,407 @@ +--- +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: .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 + programs: + additionalProperties: + 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: + fentry: + description: fentry defines the desired state of the application's + FentryPrograms. + properties: + attach_points: + description: |- + The list of points to which the program should be attached. For Fentry + programs, there will be at most one attach point, but it's being + maintained as a list for consistency with most of the other program + types. + 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 + function_name: + description: FunctionName is the name of the function + to attach the Fentry program to. + 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: + - attachid + - attachstatus + - function_name + - should_attach + - uuid + type: object + type: array + type: object + 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 + 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: + - 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)' + 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. + type: object + 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 + - 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..f329a17cc 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,103 +216,153 @@ 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 + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -310,146 +410,138 @@ 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 + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -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,84 +605,121 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -651,114 +767,128 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + 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 + 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. @@ -806,125 +936,146 @@ 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 + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + oldmapownerselector: + description: |- + 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. @@ -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..f77ae1518 100644 --- a/config/crd/bases/bpfman.io_fentryprograms.yaml +++ b/config/crd/bases/bpfman.io_fentryprograms.yaml @@ -53,8 +53,15 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -103,8 +110,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 +223,72 @@ spec: type: object type: object x-kubernetes-map-type: atomic + oldmapownerselector: + description: |- + 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..85d3b1676 100644 --- a/config/crd/bases/bpfman.io_fexitprograms.yaml +++ b/config/crd/bases/bpfman.io_fexitprograms.yaml @@ -53,8 +53,14 @@ spec: spec: description: FexitProgramSpec defines the desired state of FexitProgram properties: + attach: + type: boolean bpffunctionname: description: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -103,8 +109,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 +222,72 @@ spec: type: object type: object x-kubernetes-map-type: atomic + oldmapownerselector: + description: |- + 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..1f35c3691 100644 --- a/config/crd/bases/bpfman.io_kprobeprograms.yaml +++ b/config/crd/bases/bpfman.io_kprobeprograms.yaml @@ -61,8 +61,40 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -111,9 +143,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 +252,70 @@ 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 + 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..b4bbe7185 100644 --- a/config/crd/bases/bpfman.io_tcnsprograms.yaml +++ b/config/crd/bases/bpfman.io_tcnsprograms.yaml @@ -65,8 +65,146 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -115,77 +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. - 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 +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 @@ -312,54 +362,70 @@ 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 + 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..3ae4b3456 100644 --- a/config/crd/bases/bpfman.io_tcprograms.yaml +++ b/config/crd/bases/bpfman.io_tcprograms.yaml @@ -65,8 +65,150 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -115,82 +257,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 +267,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 +366,70 @@ 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 + 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..bb6712888 100644 --- a/config/crd/bases/bpfman.io_tcxnsprograms.yaml +++ b/config/crd/bases/bpfman.io_tcxnsprograms.yaml @@ -65,8 +65,124 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -115,77 +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 - 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 +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 @@ -312,31 +340,70 @@ 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 + 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..88074f1b7 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,8 +65,127 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -115,82 +234,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 +244,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 +343,70 @@ 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 + 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..dcc2d40b1 100644 --- a/config/crd/bases/bpfman.io_tracepointprograms.yaml +++ b/config/crd/bases/bpfman.io_tracepointprograms.yaml @@ -53,8 +53,27 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -163,13 +182,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 +231,70 @@ spec: type: object type: object x-kubernetes-map-type: atomic + oldmapownerselector: + description: |- + 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..5077d3801 100644 --- a/config/crd/bases/bpfman.io_uprobensprograms.yaml +++ b/config/crd/bases/bpfman.io_uprobensprograms.yaml @@ -69,8 +69,114 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -119,76 +225,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 +334,70 @@ 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 + 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..0bafdd660 100644 --- a/config/crd/bases/bpfman.io_uprobeprograms.yaml +++ b/config/crd/bases/bpfman.io_uprobeprograms.yaml @@ -69,8 +69,117 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -119,80 +228,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 +337,70 @@ 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 + 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..9a0cf2f5e 100644 --- a/config/crd/bases/bpfman.io_xdpnsprograms.yaml +++ b/config/crd/bases/bpfman.io_xdpnsprograms.yaml @@ -61,8 +61,132 @@ 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: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -111,69 +235,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 +245,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 +344,69 @@ 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 + oldmapownerselector: 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 + 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..1c3e9d23f 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,8 +65,133 @@ 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 + items: + enum: + - aborted + - drop + - pass + - tx + - redirect + - dispatcher_return + type: string + maxItems: 6 + type: array + required: + - interfaceselector + - priority + type: object + type: array bpffunctionname: description: |- + ANF-TODO: BpfProgramCommon is deprecated and will be removed. + MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the + key for the Programs list in the BpfApplicationSpec. Do not use in new + load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -111,74 +240,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 +250,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 +349,70 @@ 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 + 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..ba5cd989c 100644 --- a/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml +++ b/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml @@ -11,48 +11,66 @@ spec: image: url: quay.io/bpfman-bytecode/go-app-counter: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 + tcx_stats: + 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 + attach_points: + - interfaceselector: + primarynodeinterface: true + priority: 500 + direction: ingress + # - 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 + xdp_stats: + type: XDP xdp: bpffunctionname: xdp_stats - interfaceselector: - primarynodeinterface: true - priority: 55 + attach_points: + - interfaceselector: + primarynodeinterface: true + priority: 55 + - interfaceselector: + primarynodeinterface: true + priority: 100 + containers: + namespace: bpfman + pods: + matchLabels: + name: bpfman-daemon + containernames: + - bpfman + - bpfman-agent \ No newline at end of file diff --git a/config/samples/bpfman.io_v1alpha1_fentry_bpfapplication.yaml b/config/samples/bpfman.io_v1alpha1_fentry_bpfapplication.yaml new file mode 100644 index 000000000..7abf5ff64 --- /dev/null +++ b/config/samples/bpfman.io_v1alpha1_fentry_bpfapplication.yaml @@ -0,0 +1,19 @@ +apiVersion: bpfman.io/v1alpha1 +kind: BpfApplication +metadata: + labels: + app.kubernetes.io/name: bpfapplication + name: bpfapplication-fentry +spec: + # Select all nodes + nodeselector: {} + bytecode: + image: + url: quay.io/bpfman-bytecode/fentry:latest + programs: + test_fentry: + type: Fentry + fentry: + bpffunctionname: test_fentry + function_name: do_unlinkat + attach: true \ No newline at end of file diff --git a/controllers/app-agent/application-program.go b/controllers/app-agent/application-program.go new file mode 100644 index 000000000..e551891a8 --- /dev/null +++ b/controllers/app-agent/application-program.go @@ -0,0 +1,505 @@ +/* +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" + + 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) { + r.Logger.Info("Enter BpfApplication Reconcile", "Name", req.Name) + + // 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 + + // 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) + } + + 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. + bpfAppState, bpfAppStateNew, err := r.getBpfAppState(ctx, true) + if err != nil { + r.Logger.Error(err, "failed to get BpfApplicationState") + return ctrl.Result{}, err + } + + // 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 = bpfAppState.DeepCopy() + } + + r.Logger.Info("From getBpfAppState", "new", bpfAppStateNew) + + r.currentAppState = bpfAppState + + r.Logger.Info("Calling reconcileLoad()") + + // Make sure the BpfApplication code is loaded on the node. + 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 + + // Reconcile each program in the BpfApplication + for progName, prog := range a.Spec.Programs { + progState, ok := bpfAppState.Spec.Programs[progName] + if !ok { + // 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("XdpProgramState not found"), + "XdpProgramState not found", "App Name", r.currentApp.Name, "Program Name", progName) + 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, "Program Name", progName, "Type", prog.Type) + } else { + progState.ProgramAttachStatus = bpfmaniov1alpha1.BpfProgCondAttached + r.Logger.Info("reconcile success", "App Name", r.currentApp.Name, "Program Name", progName, "Type", prog.Type) + } + + bpfAppState.Spec.Programs[progName] = progState + + 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 +} + +// 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{ + AppLoadStatus: bpfmaniov1alpha1.BpfProgCondNotLoaded, + UpdateCount: 0, + Programs: map[string]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 { + if len(bpfAppState.Spec.Programs) != 0 { + return fmt.Errorf("BpfApplicationState programs list has already been initialized") + } + + for progName, prog := range r.currentApp.Spec.Programs { + progState := bpfmaniov1alpha1.BpfApplicationProgramState{ + Type: prog.Type, + } + switch prog.Type { + case bpfmaniov1alpha1.ProgTypeFentry: + progState.Fentry = &bpfmaniov1alpha1.FentryProgramInfoState{} + 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{} + 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{} + default: + panic(fmt.Sprintf("unexpected v1alpha1.EBPFProgType: %#v", prog.Type)) + } + + bpfAppState.Spec.Programs[progName] = progState + } + + return nil +} diff --git a/controllers/app-agent/application-program_test.go b/controllers/app-agent/application-program_test.go new file mode 100644 index 000000000..d7a8ac782 --- /dev/null +++ b/controllers/app-agent/application-program_test.go @@ -0,0 +1,235 @@ +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" + 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" + ) + + 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, + } + + // A AppProgram object with metadata and spec. + programMap := make(map[string]bpfmaniov1alpha1.BpfApplicationProgram) + + programMap[xdpBpfFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + Type: bpfmaniov1alpha1.ProgTypeXDP, + XDP: &bpfmaniov1alpha1.XdpProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: xdpBpfFunctionName, + OldMapOwnerSelector: metav1.LabelSelector{}, + }, + AttachPoints: []bpfmaniov1alpha1.XdpAttachInfo{xdpAttachInfo}, + }, + } + + tcxAttachInfo := bpfmaniov1alpha1.TcxAttachInfo{ + InterfaceSelector: interfaceSelector, + Containers: nil, + Direction: "ingress", + Priority: int32(priority), + } + + programMap[tcxBpfFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + Type: bpfmaniov1alpha1.ProgTypeTCX, + TCX: &bpfmaniov1alpha1.TcxProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: tcxBpfFunctionName, + OldMapOwnerSelector: metav1.LabelSelector{}, + }, + AttachPoints: []bpfmaniov1alpha1.TcxAttachInfo{tcxAttachInfo}, + }, + } + + programMap[fentryBpfFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + Type: bpfmaniov1alpha1.ProgTypeFentry, + Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: fentryBpfFunctionName, + OldMapOwnerSelector: metav1.LabelSelector{}, + }, + FentryAttachInfo: bpfmaniov1alpha1.FentryAttachInfo{Attach: true}, + }, + } + + bpfApp := &bpfmaniov1alpha1.BpfApplication{ + ObjectMeta: metav1.ObjectMeta{ + Name: appProgramName, + }, + Spec: bpfmaniov1alpha1.BpfApplicationSpec{ + BpfAppCommon: bpfmaniov1alpha1.BpfAppCommon{ + NodeSelector: metav1.LabelSelector{}, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + Programs: programMap, + }, + } + + // 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)) + + currentProgram := programMap[xdpBpfFunctionName] + + attachPoint := bpfAppState2.Spec.Programs[xdpBpfFunctionName].XDP.AttachPoints[0] + + xdpReconciler := &XdpProgramReconciler{ + ReconcilerCommon: rc, + ProgramReconcilerCommon: ProgramReconcilerCommon{ + appCommon: bpfmaniov1alpha1.BpfAppCommon{ + NodeSelector: metav1.LabelSelector{}, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + currentProgram: ¤tProgram, + 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/common.go b/controllers/app-agent/common.go new file mode 100644 index 000000000..cddaa7be6 --- /dev/null +++ b/controllers/app-agent/common.go @@ -0,0 +1,531 @@ +/* +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) + 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 + 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 { + rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondBytecodeSelectorError) + return false, err + } + 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()) + if err := bpfmanagentinternal.UnloadBpfmanProgram(ctx, r.BpfmanClient, *rec.getAttachId()); err != nil { + rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotUnloaded) + r.Logger.Error(err, "Failed to detach eBPF Program") + return false, err + } + + r.Logger.Info("Calling bpfman to attach eBPF Program") + attachId, err := bpfmanagentinternal.LoadBpfmanProgram(ctx, r.BpfmanClient, loadRequest) + if err != nil { + rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotLoaded) + r.Logger.Error(err, "Failed to attach eBPF Program") + return false, err + } + 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 { + rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondBytecodeSelectorError) + return false, err + } + r.Logger.Info("Calling bpfman to attach eBPF Program on node") + attachId, err := bpfmanagentinternal.LoadBpfmanProgram(ctx, r.BpfmanClient, loadRequest) + if err != nil { + rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotLoaded) + r.Logger.Error(err, "Failed to attach eBPF Program") + return false, err + } + 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 { + rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotUnloaded) + r.Logger.Error(err, "Failed to detach eBPF Program") + return false, err + } + 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/fentry-program.go b/controllers/app-agent/fentry-program.go new file mode 100644 index 000000000..7466ead96 --- /dev/null +++ b/controllers/app-agent/fentry-program.go @@ -0,0 +1,256 @@ +/* +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" + "github.com/google/uuid" + + 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 + // ANF-TODO: appCommon is needed to load the program. It won't be needed + // after the load/attch split is ready. + currentAttachPoint *bpfmaniov1alpha1.FentryAttachInfoState +} + +func (r *FentryProgramReconciler) getProgId() *uint32 { + return r.currentProgramState.ProgramId +} + +func (r *FentryProgramReconciler) getProgType() internal.ProgramType { + return internal.Tc +} + +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.currentAttachPoint.ShouldAttach +} + +func (r *FentryProgramReconciler) getUUID() string { + return r.currentAttachPoint.UUID +} + +func (r *FentryProgramReconciler) getAttachId() *uint32 { + return r.currentAttachPoint.AttachId +} + +func (r *FentryProgramReconciler) setAttachId(id *uint32) { + r.currentAttachPoint.AttachId = id +} + +func (r *FentryProgramReconciler) setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) { + r.currentAttachPoint.AttachStatus = status +} + +func (r *FentryProgramReconciler) getAttachStatus() bpfmaniov1alpha1.BpfProgramConditionType { + return r.currentAttachPoint.AttachStatus +} + +func (r *FentryProgramReconciler) getLoadRequest(mapOwnerId *uint32) (*gobpfman.LoadRequest, error) { + r.Logger.Info("Getting load request", "bpfFunctionName", r.currentProgram.Fentry.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) + } + + loadRequest := gobpfman.LoadRequest{ + Bytecode: bytecode, + Name: r.currentProgram.Fentry.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.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 *FentryProgramReconciler) updateAttachInfo(ctx context.Context, isBeingDeleted bool) error { + r.Logger.Info("Fentry 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.Fentry.AttachPoints { + r.Logger.Info("Setting ShouldAttach to false", "index", i) + r.currentProgramState.Fentry.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 + } + + // ANF-TODO: Fentry and Fexit just have a single attach point, so we don't + // have to do a loop here. This makes them different from most of the other + // program types, so we'd have to handle this if we try to make this + // function common. + expectedAttachPoints, error := r.getExpectedAttachPoints(ctx, r.currentProgram.Fentry.FentryAttachInfo) + 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.Fentry.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.Fentry.AttachPoints = append(r.currentProgramState.Fentry.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 *FentryProgramReconciler) findAttachPoint(attachInfoState bpfmaniov1alpha1.FentryAttachInfoState) *int { + for i, a := range r.currentProgramState.Fentry.AttachPoints { + // attachInfoState is the same as a if the the following fields are the + // same: FunctionName. + if a.FunctionName == attachInfoState.FunctionName { + 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 *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, 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.Fentry.AttachPoints { + r.currentAttachPoint = &r.currentProgramState.Fentry.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.Fentry.AttachPoints = r.removeAttachPoints(r.currentProgramState.Fentry.AttachPoints, attachPointsToRemove) + } + + return lastReconcileAttachmentError +} + +// 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, + }, + FunctionName: r.currentProgram.Fentry.FunctionName, + } + attachPoints = append(attachPoints, attachPoint) + } + + return attachPoints, nil +} 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-agent/tcx-program.go b/controllers/app-agent/tcx-program.go new file mode 100644 index 000000000..1fa857923 --- /dev/null +++ b/controllers/app-agent/tcx-program.go @@ -0,0 +1,311 @@ +/* +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) { + 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.TCX.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 + } + + loadRequest := gobpfman.LoadRequest{ + Bytecode: bytecode, + Name: r.currentProgram.TCX.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/xdp-program.go b/controllers/app-agent/xdp-program.go new file mode 100644 index 000000000..5763682ec --- /dev/null +++ b/controllers/app-agent/xdp-program.go @@ -0,0 +1,332 @@ +/* +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) { + 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.XDP.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 + } + + loadRequest := gobpfman.LoadRequest{ + Bytecode: bytecode, + Name: r.currentProgram.XDP.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-operator/application-program_test.go b/controllers/app-operator/application-program_test.go new file mode 100644 index 000000000..75363cb18 --- /dev/null +++ b/controllers/app-operator/application-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, + } + + // A AppProgram object with metadata and spec. + programMap := make(map[string]bpfmaniov1alpha1.BpfApplicationProgram) + + programMap[xdpBpfFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + Type: bpfmaniov1alpha1.ProgTypeXDP, + XDP: &bpfmaniov1alpha1.XdpProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: xdpBpfFunctionName, + OldMapOwnerSelector: metav1.LabelSelector{}, + }, + AttachPoints: []bpfmaniov1alpha1.XdpAttachInfo{attachInfo}, + }, + } + + // 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: programMap, + }, + } + + // 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: map[string]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-programs.go b/controllers/app-operator/application-programs.go new file mode 100644 index 000000000..831c550eb --- /dev/null +++ b/controllers/app-operator/application-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..49398cf18 100644 --- a/controllers/bpfman-agent/application-program_test.go +++ b/controllers/bpfman-agent/application-program_test.go @@ -52,6 +52,35 @@ func TestBpfApplicationControllerCreate(t *testing.T) { ) // A AppProgram object with metadata and spec. + programMap := make(map[string]bpfmaniov1alpha1.BpfApplicationProgram) + + programMap[bpfFentryFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + Type: bpfmaniov1alpha1.ProgTypeFentry, + Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfFentryFunctionName, + }, + FentryLoadInfo: bpfmaniov1alpha1.FentryLoadInfo{FunctionName: fentryFunctionName}, + FentryAttachInfo: bpfmaniov1alpha1.FentryAttachInfo{Attach: true}, + }, + } + + programMap[bpfKprobeFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + Type: bpfmaniov1alpha1.ProgTypeKprobe, + Kprobe: &bpfmaniov1alpha1.KprobeProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfKprobeFunctionName, + }, + AttachPoints: []bpfmaniov1alpha1.KprobeAttachInfo{ + { + FunctionName: kprobeFunctionName, + Offset: uint64(kprobeOffset), + RetProbe: kprobeRetprobe, + }, + }, + }, + } + App := &bpfmaniov1alpha1.BpfApplication{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -63,28 +92,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: programMap, }, } 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..e604cef8e 100644 --- a/controllers/bpfman-operator/application-program_test.go +++ b/controllers/bpfman-operator/application-program_test.go @@ -56,7 +56,52 @@ 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. + + programMap := make(map[string]bpfmaniov1alpha1.BpfApplicationProgram) + + programMap[bpfFentryFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + Type: bpfmaniov1alpha1.ProgTypeFentry, + Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfFentryFunctionName, + }, + FentryLoadInfo: bpfmaniov1alpha1.FentryLoadInfo{FunctionName: functionFentryName}, + FentryAttachInfo: bpfmaniov1alpha1.FentryAttachInfo{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: name, @@ -68,37 +113,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: programMap, }, } 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 + } +} From ce4d79d89903e67972dfbf0a6210e607f577ed68 Mon Sep 17 00:00:00 2001 From: Andre Fredette Date: Sun, 26 Jan 2025 12:37:32 -0500 Subject: [PATCH 2/3] Update TODO list, rename some files, fix fentry Signed-off-by: Andre Fredette --- TODO.md | 114 +++++++++++++++++- .../bpfman.io_v1alpha1_bpfapplication.yaml | 14 ++- ...man.io_v1alpha1_fentry_bpfapplication.yaml | 19 --- ...n-program.go => cl-application-program.go} | 0 ...test.go => cl-application-program_test.go} | 0 ...fentry-program.go => cl-fentry-program.go} | 8 +- .../{tcx-program.go => cl-tcx-program.go} | 4 +- .../{xdp-program.go => cl-xdp-program.go} | 4 +- controllers/app-agent/common.go | 93 ++++++++------ ...test.go => application-cl-program_test.go} | 0 ...programs.go => application-cl-programs.go} | 0 11 files changed, 182 insertions(+), 74 deletions(-) delete mode 100644 config/samples/bpfman.io_v1alpha1_fentry_bpfapplication.yaml rename controllers/app-agent/{application-program.go => cl-application-program.go} (100%) rename controllers/app-agent/{application-program_test.go => cl-application-program_test.go} (100%) rename controllers/app-agent/{fentry-program.go => cl-fentry-program.go} (98%) rename controllers/app-agent/{tcx-program.go => cl-tcx-program.go} (99%) rename controllers/app-agent/{xdp-program.go => cl-xdp-program.go} (99%) rename controllers/app-operator/{application-program_test.go => application-cl-program_test.go} (100%) rename controllers/app-operator/{application-programs.go => application-cl-programs.go} (100%) diff --git a/TODO.md b/TODO.md index ce2551825..afb57a35b 100644 --- a/TODO.md +++ b/TODO.md @@ -1,12 +1,113 @@ +# 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: +## Updated & working APIs: - apis/v1alpha1/fentryProgram_types.go - apis/v1alpha1/xdpProgram_types.go @@ -16,11 +117,11 @@ Updated & working APIs: Note: the rest are partially updated. -New Agent: +## New Agent: - controllers/app-agent -New Operator: +## New Operator: - controllers/app-operator @@ -28,15 +129,18 @@ 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: +# 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: +# 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. diff --git a/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml b/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml index ba5cd989c..d60fba24a 100644 --- a/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml +++ b/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml @@ -9,7 +9,7 @@ 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: @@ -34,7 +34,7 @@ spec: tcx_stats: type: TCX tcx: - bpffunctionname: tcx_stats + bpffunctionname: tcx_next attach_points: - interfaceselector: primarynodeinterface: true @@ -58,7 +58,7 @@ spec: xdp_stats: type: XDP xdp: - bpffunctionname: xdp_stats + bpffunctionname: xdp_pass attach_points: - interfaceselector: primarynodeinterface: true @@ -73,4 +73,10 @@ spec: name: bpfman-daemon containernames: - bpfman - - bpfman-agent \ No newline at end of file + - bpfman-agent + test_fentry: + type: Fentry + fentry: + bpffunctionname: fentry_test + function_name: do_unlinkat + attach: true \ No newline at end of file diff --git a/config/samples/bpfman.io_v1alpha1_fentry_bpfapplication.yaml b/config/samples/bpfman.io_v1alpha1_fentry_bpfapplication.yaml deleted file mode 100644 index 7abf5ff64..000000000 --- a/config/samples/bpfman.io_v1alpha1_fentry_bpfapplication.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: bpfman.io/v1alpha1 -kind: BpfApplication -metadata: - labels: - app.kubernetes.io/name: bpfapplication - name: bpfapplication-fentry -spec: - # Select all nodes - nodeselector: {} - bytecode: - image: - url: quay.io/bpfman-bytecode/fentry:latest - programs: - test_fentry: - type: Fentry - fentry: - bpffunctionname: test_fentry - function_name: do_unlinkat - attach: true \ No newline at end of file diff --git a/controllers/app-agent/application-program.go b/controllers/app-agent/cl-application-program.go similarity index 100% rename from controllers/app-agent/application-program.go rename to controllers/app-agent/cl-application-program.go diff --git a/controllers/app-agent/application-program_test.go b/controllers/app-agent/cl-application-program_test.go similarity index 100% rename from controllers/app-agent/application-program_test.go rename to controllers/app-agent/cl-application-program_test.go diff --git a/controllers/app-agent/fentry-program.go b/controllers/app-agent/cl-fentry-program.go similarity index 98% rename from controllers/app-agent/fentry-program.go rename to controllers/app-agent/cl-fentry-program.go index 7466ead96..e38a42736 100644 --- a/controllers/app-agent/fentry-program.go +++ b/controllers/app-agent/cl-fentry-program.go @@ -47,7 +47,7 @@ func (r *FentryProgramReconciler) getProgId() *uint32 { } func (r *FentryProgramReconciler) getProgType() internal.ProgramType { - return internal.Tc + return internal.Tracing } func (r *FentryProgramReconciler) getNode() *v1.Node { @@ -74,8 +74,8 @@ func (r *FentryProgramReconciler) setAttachId(id *uint32) { r.currentAttachPoint.AttachId = id } -func (r *FentryProgramReconciler) setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) { - r.currentAttachPoint.AttachStatus = status +func (r *FentryProgramReconciler) setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) bool { + return updateSimpleStatus(&r.currentAttachPoint.AttachStatus, status) } func (r *FentryProgramReconciler) getAttachStatus() bpfmaniov1alpha1.BpfProgramConditionType { @@ -186,7 +186,7 @@ func (r *FentryProgramReconciler) processAttachInfo(ctx context.Context, mapOwne "mapOwnerStatus", mapOwnerStatus) // Get existing ebpf state from bpfman. - loadedBpfPrograms, err := bpfmanagentinternal.ListBpfmanPrograms(ctx, r.BpfmanClient, internal.Tc) + 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) diff --git a/controllers/app-agent/tcx-program.go b/controllers/app-agent/cl-tcx-program.go similarity index 99% rename from controllers/app-agent/tcx-program.go rename to controllers/app-agent/cl-tcx-program.go index 1fa857923..b850d7e94 100644 --- a/controllers/app-agent/tcx-program.go +++ b/controllers/app-agent/cl-tcx-program.go @@ -73,8 +73,8 @@ func (r *TcxProgramReconciler) setAttachId(id *uint32) { r.currentAttachPoint.AttachId = id } -func (r *TcxProgramReconciler) setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) { - r.currentAttachPoint.AttachStatus = status +func (r *TcxProgramReconciler) setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) bool { + return updateSimpleStatus(&r.currentAttachPoint.AttachStatus, status) } func (r *TcxProgramReconciler) getAttachStatus() bpfmaniov1alpha1.BpfProgramConditionType { diff --git a/controllers/app-agent/xdp-program.go b/controllers/app-agent/cl-xdp-program.go similarity index 99% rename from controllers/app-agent/xdp-program.go rename to controllers/app-agent/cl-xdp-program.go index 5763682ec..afe31c86c 100644 --- a/controllers/app-agent/xdp-program.go +++ b/controllers/app-agent/cl-xdp-program.go @@ -73,8 +73,8 @@ func (r *XdpProgramReconciler) setAttachId(id *uint32) { r.currentAttachPoint.AttachId = id } -func (r *XdpProgramReconciler) setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) { - r.currentAttachPoint.AttachStatus = status +func (r *XdpProgramReconciler) setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) bool { + return updateSimpleStatus(&r.currentAttachPoint.AttachStatus, status) } func (r *XdpProgramReconciler) getAttachStatus() bpfmaniov1alpha1.BpfProgramConditionType { diff --git a/controllers/app-agent/common.go b/controllers/app-agent/common.go index cddaa7be6..bbf733783 100644 --- a/controllers/app-agent/common.go +++ b/controllers/app-agent/common.go @@ -108,7 +108,7 @@ type ProgramReconciler interface { getUUID() string getAttachId() *uint32 setAttachId(id *uint32) - setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) + setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) bool getAttachStatus() bpfmaniov1alpha1.BpfProgramConditionType } @@ -447,49 +447,64 @@ func (r *ReconcilerCommon) reconcileBpfAttachment( // Confirm it's in the correct state. loadRequest, err := rec.getLoadRequest(mapOwnerStatus.mapOwnerId) if err != nil { - rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondBytecodeSelectorError) - return false, err - } - 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()) - if err := bpfmanagentinternal.UnloadBpfmanProgram(ctx, r.BpfmanClient, *rec.getAttachId()); err != nil { - rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotUnloaded) - r.Logger.Error(err, "Failed to detach eBPF Program") - return false, err - } - - r.Logger.Info("Calling bpfman to attach eBPF Program") - attachId, err := bpfmanagentinternal.LoadBpfmanProgram(ctx, r.BpfmanClient, loadRequest) - if err != nil { - rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotLoaded) - r.Logger.Error(err, "Failed to attach eBPF Program") + r.Logger.Error(err, "Failed to get LoadRequest") + if rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondBytecodeSelectorError) { return false, err } - 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) + 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 { - rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondBytecodeSelectorError) - return false, err - } - r.Logger.Info("Calling bpfman to attach eBPF Program on node") - attachId, err := bpfmanagentinternal.LoadBpfmanProgram(ctx, r.BpfmanClient, loadRequest) - if err != nil { - rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotLoaded) - r.Logger.Error(err, "Failed to attach eBPF Program") - return false, err + 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) + } } - rec.setAttachId(attachId) - rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondAttached) } case false: switch isAttached { @@ -497,18 +512,20 @@ func (r *ReconcilerCommon) reconcileBpfAttachment( // 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 { - rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotUnloaded) r.Logger.Error(err, "Failed to detach eBPF Program") - return false, err + if rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotUnloaded) { + return false, err + } + } else { + rec.setAttachStatus(bpfmaniov1alpha1.BpfProgCondNotAttached) } - 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. + // The BPF program was successfully reconciled. remove := !rec.shouldAttach() && rec.getAttachStatus() == bpfmaniov1alpha1.BpfProgCondNotAttached return remove, nil } diff --git a/controllers/app-operator/application-program_test.go b/controllers/app-operator/application-cl-program_test.go similarity index 100% rename from controllers/app-operator/application-program_test.go rename to controllers/app-operator/application-cl-program_test.go diff --git a/controllers/app-operator/application-programs.go b/controllers/app-operator/application-cl-programs.go similarity index 100% rename from controllers/app-operator/application-programs.go rename to controllers/app-operator/application-cl-programs.go From 5e3e29ccc536fab90c7d32aa48d7cdac7833f79f Mon Sep 17 00:00:00 2001 From: Andre Fredette Date: Sat, 1 Feb 2025 09:48:15 -0500 Subject: [PATCH 3/3] Change back to using slices for the program lists. Signed-off-by: Andre Fredette --- apis/v1alpha1/bpfApplicationState_types.go | 24 +- apis/v1alpha1/bpfApplication_types.go | 7 +- apis/v1alpha1/fentryProgram_types.go | 12 +- apis/v1alpha1/shared_types.go | 34 +- apis/v1alpha1/xdpProgram_types.go | 1 - apis/v1alpha1/zz_generated.deepcopy.go | 55 ++-- ...bpfman-operator.clusterserviceversion.yaml | 28 +- .../manifests/bpfman.io_bpfapplications.yaml | 237 ++++++++------ .../bpfman.io_bpfapplicationstates.yaml | 287 +++++++++++++++-- .../bpfman.io_bpfnsapplications.yaml | 80 ++--- .../manifests/bpfman.io_fentryprograms.yaml | 16 +- bundle/manifests/bpfman.io_fexitprograms.yaml | 16 +- .../manifests/bpfman.io_kprobeprograms.yaml | 16 +- bundle/manifests/bpfman.io_tcnsprograms.yaml | 16 +- bundle/manifests/bpfman.io_tcprograms.yaml | 16 +- bundle/manifests/bpfman.io_tcxnsprograms.yaml | 16 +- bundle/manifests/bpfman.io_tcxprograms.yaml | 16 +- .../bpfman.io_tracepointprograms.yaml | 16 +- .../manifests/bpfman.io_uprobensprograms.yaml | 16 +- .../manifests/bpfman.io_uprobeprograms.yaml | 16 +- bundle/manifests/bpfman.io_xdpnsprograms.yaml | 16 +- bundle/manifests/bpfman.io_xdpprograms.yaml | 19 +- .../crd/bases/bpfman.io_bpfapplications.yaml | 237 ++++++++------ .../bases/bpfman.io_bpfapplicationstates.yaml | 291 ++++++++++++++++-- .../bases/bpfman.io_bpfnsapplications.yaml | 80 ++--- .../crd/bases/bpfman.io_fentryprograms.yaml | 16 +- config/crd/bases/bpfman.io_fexitprograms.yaml | 16 +- .../crd/bases/bpfman.io_kprobeprograms.yaml | 16 +- config/crd/bases/bpfman.io_tcnsprograms.yaml | 16 +- config/crd/bases/bpfman.io_tcprograms.yaml | 16 +- config/crd/bases/bpfman.io_tcxnsprograms.yaml | 16 +- config/crd/bases/bpfman.io_tcxprograms.yaml | 16 +- .../bases/bpfman.io_tracepointprograms.yaml | 16 +- .../crd/bases/bpfman.io_uprobensprograms.yaml | 16 +- .../crd/bases/bpfman.io_uprobeprograms.yaml | 16 +- config/crd/bases/bpfman.io_xdpnsprograms.yaml | 16 +- config/crd/bases/bpfman.io_xdpprograms.yaml | 19 +- .../bpfman.io_v1alpha1_bpfapplication.yaml | 22 +- .../app-agent/cl-application-program.go | 110 +++++-- .../app-agent/cl-application-program_test.go | 51 +-- controllers/app-agent/cl-fentry-program.go | 150 +++------ controllers/app-agent/cl-tcx-program.go | 16 +- controllers/app-agent/cl-xdp-program.go | 13 +- controllers/app-agent/common.go | 2 +- .../application-cl-program_test.go | 18 +- .../bpfman-agent/application-program_test.go | 13 +- .../application-program_test.go | 16 +- 47 files changed, 1409 insertions(+), 765 deletions(-) diff --git a/apis/v1alpha1/bpfApplicationState_types.go b/apis/v1alpha1/bpfApplicationState_types.go index 3dedaa9c6..111f3515c 100644 --- a/apis/v1alpha1/bpfApplicationState_types.go +++ b/apis/v1alpha1/bpfApplicationState_types.go @@ -35,15 +35,7 @@ import ( // // +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 { - // 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"` - + BpfProgramStateCommon `json:",inline"` // Type specifies the bpf program type // +unionDiscriminator // +kubebuilder:validation:Required @@ -55,10 +47,10 @@ type BpfApplicationProgramState struct { // +optional XDP *XdpProgramInfoState `json:"xdp,omitempty"` - // // tc defines the desired state of the application's TcPrograms. - // // +unionMember - // // +optional - // TC *TcProgramInfoState `json:"tc,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 @@ -103,6 +95,8 @@ type BpfApplicationProgramState struct { // 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 @@ -114,7 +108,7 @@ type BpfApplicationStateSpec struct { // 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 map[string]BpfApplicationProgramState `json:"programs,omitempty"` + Programs []BpfApplicationProgramState `json:"programs,omitempty"` } // +genclient @@ -125,7 +119,7 @@ type BpfApplicationStateSpec struct { // 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']" +// +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 { diff --git a/apis/v1alpha1/bpfApplication_types.go b/apis/v1alpha1/bpfApplication_types.go index a7830abdb..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,12 +129,10 @@ type BpfApplicationProgram struct { // BpfApplicationSpec defines the desired state of BpfApplication type BpfApplicationSpec struct { BpfAppCommon `json:",inline"` - // 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. The list is - // implemented as a map from the bpf function name to BpfApplicationProgram. - Programs map[string]BpfApplicationProgram `json:"programs,omitempty"` + // from this list based on the optional attach points provided. + Programs []BpfApplicationProgram `json:"programs,omitempty"` } // +genclient diff --git a/apis/v1alpha1/fentryProgram_types.go b/apis/v1alpha1/fentryProgram_types.go index c4c7e3fb4..8e6740515 100644 --- a/apis/v1alpha1/fentryProgram_types.go +++ b/apis/v1alpha1/fentryProgram_types.go @@ -79,16 +79,12 @@ type FentryProgramList struct { } type FentryProgramInfoState struct { - // The list of points to which the program should be attached. For Fentry - // programs, there will be at most one attach point, but it's being - // maintained as a list for consistency with most of the other program - // types. - // +optional - AttachPoints []FentryAttachInfoState `json:"attach_points"` + BpfProgramStateCommon `json:",inline"` + FentryLoadInfo `json:",inline"` + FentryAttachInfoState `json:",inline"` } type FentryAttachInfoState struct { AttachInfoCommon `json:",inline"` - // FunctionName is the name of the function to attach the Fentry program to. - FunctionName string `json:"function_name"` + Attach bool `json:"attach"` } diff --git a/apis/v1alpha1/shared_types.go b/apis/v1alpha1/shared_types.go index a3ca66d3c..43a573501 100644 --- a/apis/v1alpha1/shared_types.go +++ b/apis/v1alpha1/shared_types.go @@ -67,20 +67,21 @@ 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 { - // ANF-TODO: BpfProgramCommon is deprecated and will be removed. - // MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - // key for the Programs list in the BpfApplicationSpec. Do not use in new - // load/attach split code. // BpfFunctionName is the name of the function that is the entry point for the BPF // program BpfFunctionName string `json:"bpffunctionname"` - // 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. + // 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 OldMapOwnerSelector metav1.LabelSelector `json:"oldmapownerselector"` } @@ -126,7 +127,8 @@ type BpfAppStatus 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 +// 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"` @@ -138,10 +140,22 @@ type AttachInfoCommon struct { // 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 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 diff --git a/apis/v1alpha1/xdpProgram_types.go b/apis/v1alpha1/xdpProgram_types.go index 3852ffc87..b7e6e0cef 100644 --- a/apis/v1alpha1/xdpProgram_types.go +++ b/apis/v1alpha1/xdpProgram_types.go @@ -85,7 +85,6 @@ type XdpAttachInfo struct { // +optional // +kubebuilder:validation:MaxItems=6 // +kubebuilder:default:={pass,dispatcher_return} - ProceedOn []XdpProceedOnValue `json:"proceedon"` } diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index aaa429ab5..1f2589424 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -167,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) @@ -232,16 +233,17 @@ func (in *BpfApplicationProgram) DeepCopy() *BpfApplicationProgram { // 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 - if in.ProgramId != nil { - in, out := &in.ProgramId, &out.ProgramId - *out = new(uint32) - **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) @@ -270,9 +272,9 @@ func (in *BpfApplicationSpec) DeepCopyInto(out *BpfApplicationSpec) { in.BpfAppCommon.DeepCopyInto(&out.BpfAppCommon) if in.Programs != nil { in, out := &in.Programs, &out.Programs - *out = make(map[string]BpfApplicationProgram, len(*in)) - for key, val := range *in { - (*out)[key] = *val.DeepCopy() + *out = make([]BpfApplicationProgram, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) } } } @@ -351,9 +353,9 @@ func (in *BpfApplicationStateSpec) DeepCopyInto(out *BpfApplicationStateSpec) { *out = *in if in.Programs != nil { in, out := &in.Programs, &out.Programs - *out = make(map[string]BpfApplicationProgramState, len(*in)) - for key, val := range *in { - (*out)[key] = *val.DeepCopy() + *out = make([]BpfApplicationProgramState, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) } } } @@ -639,6 +641,27 @@ func (in *BpfProgramSpec) DeepCopy() *BpfProgramSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BpfProgramStateCommon) DeepCopyInto(out *BpfProgramStateCommon) { + *out = *in + 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 BpfProgramStateCommon. +func (in *BpfProgramStateCommon) DeepCopy() *BpfProgramStateCommon { + if in == nil { + return nil + } + 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 *BpfProgramStatus) DeepCopyInto(out *BpfProgramStatus) { *out = *in @@ -850,13 +873,9 @@ func (in *FentryProgramInfo) DeepCopy() *FentryProgramInfo { // 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 - if in.AttachPoints != nil { - in, out := &in.AttachPoints, &out.AttachPoints - *out = make([]FentryAttachInfoState, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } + 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. diff --git a/bundle/manifests/bpfman-operator.clusterserviceversion.yaml b/bundle/manifests/bpfman-operator.clusterserviceversion.yaml index 90fc8c56e..9e8ba006e 100644 --- a/bundle/manifests/bpfman-operator.clusterserviceversion.yaml +++ b/bundle/manifests/bpfman-operator.clusterserviceversion.yaml @@ -16,12 +16,13 @@ metadata: "spec": { "bytecode": { "image": { - "url": "quay.io/bpfman-bytecode/go-app-counter:latest" + "url": "quay.io/bpfman-bytecode/app-test:latest" } }, "nodeselector": {}, - "programs": { - "tcx_stats": { + "programs": [ + { + "bpffunctionname": "tcx_next", "tcx": { "attach_points": [ { @@ -31,12 +32,12 @@ metadata: }, "priority": 500 } - ], - "bpffunctionname": "tcx_stats" + ] }, "type": "TCX" }, - "xdp_stats": { + { + "bpffunctionname": "xdp_pass", "type": "XDP", "xdp": { "attach_points": [ @@ -64,11 +65,18 @@ metadata: }, "priority": 100 } - ], - "bpffunctionname": "xdp_stats" + ] } + }, + { + "bpffunctionname": "fentry_test", + "fentry": { + "attach": true, + "function_name": "do_unlinkat" + }, + "type": "Fentry" } - } + ] } }, { @@ -595,7 +603,7 @@ metadata: capabilities: Basic Install categories: OpenShift Optional containerImage: quay.io/bpfman/bpfman-operator:latest - createdAt: "2025-01-24T22:01:22Z" + createdAt: "2025-01-31T21:55:14Z" features.operators.openshift.io/cnf: "false" features.operators.openshift.io/cni: "false" features.operators.openshift.io/csi: "true" diff --git a/bundle/manifests/bpfman.io_bpfapplications.yaml b/bundle/manifests/bpfman.io_bpfapplications.yaml index 1f98fb808..1507d5f66 100644 --- a/bundle/manifests/bpfman.io_bpfapplications.yaml +++ b/bundle/manifests/bpfman.io_bpfapplications.yaml @@ -204,10 +204,19 @@ spec: type: object x-kubernetes-map-type: atomic programs: - additionalProperties: + description: |- + 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. @@ -218,10 +227,6 @@ spec: type: boolean bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -231,10 +236,14 @@ spec: type: string oldmapownerselector: description: |- - 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. + 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 @@ -292,10 +301,6 @@ spec: type: boolean bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -305,10 +310,14 @@ spec: type: string oldmapownerselector: description: |- - 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. + 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 @@ -392,19 +401,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -486,19 +495,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -546,6 +555,60 @@ spec: required: - bpffunctionname 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. @@ -691,19 +754,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -873,19 +936,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -954,19 +1017,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -1140,19 +1203,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -1312,19 +1375,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -1482,6 +1545,9 @@ spec: 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 @@ -1500,19 +1566,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -1560,6 +1626,8 @@ spec: required: - bpffunctionname type: object + required: + - bpffunctionname type: object x-kubernetes-validations: - message: xdp configuration is required when type is XDP, and forbidden @@ -1602,12 +1670,7 @@ spec: and forbidden otherwise rule: 'has(self.type) && self.type == ''Tracepoint'' ? has(self.tracepoint) : !has(self.tracepoint)' - description: |- - 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. The list is - implemented as a map from the bpf function name to BpfApplicationProgram. - type: object + type: array required: - bytecode - nodeselector diff --git a/bundle/manifests/bpfman.io_bpfapplicationstates.yaml b/bundle/manifests/bpfman.io_bpfapplicationstates.yaml index 817ba9dfc..fa34e7a01 100644 --- a/bundle/manifests/bpfman.io_bpfapplicationstates.yaml +++ b/bundle/manifests/bpfman.io_bpfapplicationstates.yaml @@ -54,8 +54,15 @@ spec: 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: - additionalProperties: + 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" @@ -66,16 +73,199 @@ spec: // +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. For Fentry - programs, there will be at most one attach point, but it's being - maintained as a list for consistency with most of the other program - types. + 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: @@ -87,13 +277,56 @@ spec: format: int32 type: integer attachstatus: - description: AttachStatus reflects whether the attachment - has been reconciled successfully, and if not, why. + 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 - function_name: - description: FunctionName is the name of the function - to attach the Fentry program to. + 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. @@ -106,23 +339,15 @@ spec: required: - attachid - attachstatus - - function_name + - direction + - ifname + - priority + - proceedon - should_attach - uuid type: object type: array type: object - 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 tcx: description: tcx defines the desired state of the application's TcxPrograms. @@ -145,8 +370,9 @@ spec: format: int32 type: integer attachstatus: - description: AttachStatus reflects whether the attachment - has been reconciled successfully, and if not, why. + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. type: string containerpid: description: Optional container pid to attach the @@ -230,8 +456,9 @@ spec: format: int32 type: integer attachstatus: - description: AttachStatus reflects whether the attachment - has been reconciled successfully, and if not, why. + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. type: string containerpid: description: Optional container pid to attach the @@ -287,6 +514,7 @@ spec: type: array type: object required: + - bpffunctionname - programattachstatus type: object x-kubernetes-validations: @@ -302,11 +530,7 @@ spec: and forbidden otherwise rule: 'has(self.type) && self.type == ''Fentry'' ? has(self.fentry) : !has(self.fentry)' - 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. - type: object + type: array updatecount: description: |- The number of times the BpfApplicationState has been updated. Set to 1 @@ -317,6 +541,7 @@ spec: type: integer required: - apploadstatus + - node - updatecount type: object status: diff --git a/bundle/manifests/bpfman.io_bpfnsapplications.yaml b/bundle/manifests/bpfman.io_bpfnsapplications.yaml index 45ec0d69c..3a7132595 100644 --- a/bundle/manifests/bpfman.io_bpfnsapplications.yaml +++ b/bundle/manifests/bpfman.io_bpfnsapplications.yaml @@ -353,19 +353,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -532,19 +532,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -710,19 +710,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -879,19 +879,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -1066,19 +1066,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 diff --git a/bundle/manifests/bpfman.io_fentryprograms.yaml b/bundle/manifests/bpfman.io_fentryprograms.yaml index b26a5d35c..7a39546de 100644 --- a/bundle/manifests/bpfman.io_fentryprograms.yaml +++ b/bundle/manifests/bpfman.io_fentryprograms.yaml @@ -58,10 +58,6 @@ spec: type: boolean bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -225,10 +221,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/bundle/manifests/bpfman.io_fexitprograms.yaml b/bundle/manifests/bpfman.io_fexitprograms.yaml index b71ec7519..306d5baab 100644 --- a/bundle/manifests/bpfman.io_fexitprograms.yaml +++ b/bundle/manifests/bpfman.io_fexitprograms.yaml @@ -57,10 +57,6 @@ spec: type: boolean bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -224,10 +220,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/bundle/manifests/bpfman.io_kprobeprograms.yaml b/bundle/manifests/bpfman.io_kprobeprograms.yaml index f5714de0d..d8cbe3a32 100644 --- a/bundle/manifests/bpfman.io_kprobeprograms.yaml +++ b/bundle/manifests/bpfman.io_kprobeprograms.yaml @@ -91,10 +91,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -254,10 +250,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/bundle/manifests/bpfman.io_tcnsprograms.yaml b/bundle/manifests/bpfman.io_tcnsprograms.yaml index 28b08fd72..5ba649316 100644 --- a/bundle/manifests/bpfman.io_tcnsprograms.yaml +++ b/bundle/manifests/bpfman.io_tcnsprograms.yaml @@ -201,10 +201,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -364,10 +360,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/bundle/manifests/bpfman.io_tcprograms.yaml b/bundle/manifests/bpfman.io_tcprograms.yaml index 105d4cdfa..c30b8719d 100644 --- a/bundle/manifests/bpfman.io_tcprograms.yaml +++ b/bundle/manifests/bpfman.io_tcprograms.yaml @@ -205,10 +205,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -368,10 +364,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/bundle/manifests/bpfman.io_tcxnsprograms.yaml b/bundle/manifests/bpfman.io_tcxnsprograms.yaml index 62a4fbaa6..1fffe83ed 100644 --- a/bundle/manifests/bpfman.io_tcxnsprograms.yaml +++ b/bundle/manifests/bpfman.io_tcxnsprograms.yaml @@ -179,10 +179,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -342,10 +338,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/bundle/manifests/bpfman.io_tcxprograms.yaml b/bundle/manifests/bpfman.io_tcxprograms.yaml index 43f88689a..f0b1acf7a 100644 --- a/bundle/manifests/bpfman.io_tcxprograms.yaml +++ b/bundle/manifests/bpfman.io_tcxprograms.yaml @@ -182,10 +182,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -345,10 +341,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/bundle/manifests/bpfman.io_tracepointprograms.yaml b/bundle/manifests/bpfman.io_tracepointprograms.yaml index 4d70631f0..32348db78 100644 --- a/bundle/manifests/bpfman.io_tracepointprograms.yaml +++ b/bundle/manifests/bpfman.io_tracepointprograms.yaml @@ -70,10 +70,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -233,10 +229,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/bundle/manifests/bpfman.io_uprobensprograms.yaml b/bundle/manifests/bpfman.io_uprobensprograms.yaml index 769b4c51f..43bad0bcf 100644 --- a/bundle/manifests/bpfman.io_uprobensprograms.yaml +++ b/bundle/manifests/bpfman.io_uprobensprograms.yaml @@ -173,10 +173,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -336,10 +332,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/bundle/manifests/bpfman.io_uprobeprograms.yaml b/bundle/manifests/bpfman.io_uprobeprograms.yaml index b509ebcd4..81c5017c0 100644 --- a/bundle/manifests/bpfman.io_uprobeprograms.yaml +++ b/bundle/manifests/bpfman.io_uprobeprograms.yaml @@ -176,10 +176,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -339,10 +335,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/bundle/manifests/bpfman.io_xdpnsprograms.yaml b/bundle/manifests/bpfman.io_xdpnsprograms.yaml index 09fa8a530..88c25c37d 100644 --- a/bundle/manifests/bpfman.io_xdpnsprograms.yaml +++ b/bundle/manifests/bpfman.io_xdpnsprograms.yaml @@ -183,10 +183,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -346,10 +342,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/bundle/manifests/bpfman.io_xdpprograms.yaml b/bundle/manifests/bpfman.io_xdpprograms.yaml index b20202509..498fc08b2 100644 --- a/bundle/manifests/bpfman.io_xdpprograms.yaml +++ b/bundle/manifests/bpfman.io_xdpprograms.yaml @@ -170,6 +170,9 @@ spec: 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 @@ -188,10 +191,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -351,10 +350,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/crd/bases/bpfman.io_bpfapplications.yaml b/config/crd/bases/bpfman.io_bpfapplications.yaml index 9890105f3..e7b87d71e 100644 --- a/config/crd/bases/bpfman.io_bpfapplications.yaml +++ b/config/crd/bases/bpfman.io_bpfapplications.yaml @@ -204,10 +204,19 @@ spec: type: object x-kubernetes-map-type: atomic programs: - additionalProperties: + description: |- + 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. @@ -218,10 +227,6 @@ spec: type: boolean bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -231,10 +236,14 @@ spec: type: string oldmapownerselector: description: |- - 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. + 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 @@ -292,10 +301,6 @@ spec: type: boolean bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -305,10 +310,14 @@ spec: type: string oldmapownerselector: description: |- - 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. + 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 @@ -392,19 +401,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -486,19 +495,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -546,6 +555,60 @@ spec: required: - bpffunctionname 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. @@ -691,19 +754,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -873,19 +936,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -954,19 +1017,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -1140,19 +1203,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -1312,19 +1375,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -1482,6 +1545,9 @@ spec: 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 @@ -1500,19 +1566,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -1560,6 +1626,8 @@ spec: required: - bpffunctionname type: object + required: + - bpffunctionname type: object x-kubernetes-validations: - message: xdp configuration is required when type is XDP, and forbidden @@ -1602,12 +1670,7 @@ spec: and forbidden otherwise rule: 'has(self.type) && self.type == ''Tracepoint'' ? has(self.tracepoint) : !has(self.tracepoint)' - description: |- - 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. The list is - implemented as a map from the bpf function name to BpfApplicationProgram. - type: object + type: array required: - bytecode - nodeselector diff --git a/config/crd/bases/bpfman.io_bpfapplicationstates.yaml b/config/crd/bases/bpfman.io_bpfapplicationstates.yaml index bc0f24b0f..81fbe5f3e 100644 --- a/config/crd/bases/bpfman.io_bpfapplicationstates.yaml +++ b/config/crd/bases/bpfman.io_bpfapplicationstates.yaml @@ -15,6 +15,9 @@ spec: scope: Cluster versions: - additionalPrinterColumns: + - jsonPath: .spec.node + name: Node + type: string - jsonPath: .status.conditions[0].reason name: Status type: string @@ -27,7 +30,6 @@ spec: 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: |- @@ -54,8 +56,15 @@ spec: 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: - additionalProperties: + 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" @@ -66,16 +75,199 @@ spec: // +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. For Fentry - programs, there will be at most one attach point, but it's being - maintained as a list for consistency with most of the other program - types. + 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: @@ -87,13 +279,56 @@ spec: format: int32 type: integer attachstatus: - description: AttachStatus reflects whether the attachment - has been reconciled successfully, and if not, why. + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. type: string - function_name: - description: FunctionName is the name of the function - to attach the Fentry program to. + 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. @@ -106,23 +341,15 @@ spec: required: - attachid - attachstatus - - function_name + - direction + - ifname + - priority + - proceedon - should_attach - uuid type: object type: array type: object - 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 tcx: description: tcx defines the desired state of the application's TcxPrograms. @@ -145,8 +372,9 @@ spec: format: int32 type: integer attachstatus: - description: AttachStatus reflects whether the attachment - has been reconciled successfully, and if not, why. + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. type: string containerpid: description: Optional container pid to attach the @@ -230,8 +458,9 @@ spec: format: int32 type: integer attachstatus: - description: AttachStatus reflects whether the attachment - has been reconciled successfully, and if not, why. + description: |- + AttachStatus reflects whether the attachment has been reconciled + successfully, and if not, why. type: string containerpid: description: Optional container pid to attach the @@ -287,6 +516,7 @@ spec: type: array type: object required: + - bpffunctionname - programattachstatus type: object x-kubernetes-validations: @@ -302,11 +532,7 @@ spec: and forbidden otherwise rule: 'has(self.type) && self.type == ''Fentry'' ? has(self.fentry) : !has(self.fentry)' - 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. - type: object + type: array updatecount: description: |- The number of times the BpfApplicationState has been updated. Set to 1 @@ -317,6 +543,7 @@ spec: type: integer required: - apploadstatus + - node - updatecount type: object status: diff --git a/config/crd/bases/bpfman.io_bpfnsapplications.yaml b/config/crd/bases/bpfman.io_bpfnsapplications.yaml index f329a17cc..172ebd916 100644 --- a/config/crd/bases/bpfman.io_bpfnsapplications.yaml +++ b/config/crd/bases/bpfman.io_bpfnsapplications.yaml @@ -353,19 +353,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -532,19 +532,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -710,19 +710,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -879,19 +879,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 @@ -1066,19 +1066,19 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string oldmapownerselector: description: |- - 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. + 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 diff --git a/config/crd/bases/bpfman.io_fentryprograms.yaml b/config/crd/bases/bpfman.io_fentryprograms.yaml index f77ae1518..c88eb22e4 100644 --- a/config/crd/bases/bpfman.io_fentryprograms.yaml +++ b/config/crd/bases/bpfman.io_fentryprograms.yaml @@ -58,10 +58,6 @@ spec: type: boolean bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -225,10 +221,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/crd/bases/bpfman.io_fexitprograms.yaml b/config/crd/bases/bpfman.io_fexitprograms.yaml index 85d3b1676..f72982f0d 100644 --- a/config/crd/bases/bpfman.io_fexitprograms.yaml +++ b/config/crd/bases/bpfman.io_fexitprograms.yaml @@ -57,10 +57,6 @@ spec: type: boolean bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -224,10 +220,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/crd/bases/bpfman.io_kprobeprograms.yaml b/config/crd/bases/bpfman.io_kprobeprograms.yaml index 1f35c3691..ee4f9ee99 100644 --- a/config/crd/bases/bpfman.io_kprobeprograms.yaml +++ b/config/crd/bases/bpfman.io_kprobeprograms.yaml @@ -91,10 +91,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -254,10 +250,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/crd/bases/bpfman.io_tcnsprograms.yaml b/config/crd/bases/bpfman.io_tcnsprograms.yaml index b4bbe7185..e5e84bd5e 100644 --- a/config/crd/bases/bpfman.io_tcnsprograms.yaml +++ b/config/crd/bases/bpfman.io_tcnsprograms.yaml @@ -201,10 +201,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -364,10 +360,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/crd/bases/bpfman.io_tcprograms.yaml b/config/crd/bases/bpfman.io_tcprograms.yaml index 3ae4b3456..371c61f9b 100644 --- a/config/crd/bases/bpfman.io_tcprograms.yaml +++ b/config/crd/bases/bpfman.io_tcprograms.yaml @@ -205,10 +205,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -368,10 +364,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/crd/bases/bpfman.io_tcxnsprograms.yaml b/config/crd/bases/bpfman.io_tcxnsprograms.yaml index bb6712888..7afb69adb 100644 --- a/config/crd/bases/bpfman.io_tcxnsprograms.yaml +++ b/config/crd/bases/bpfman.io_tcxnsprograms.yaml @@ -179,10 +179,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -342,10 +338,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/crd/bases/bpfman.io_tcxprograms.yaml b/config/crd/bases/bpfman.io_tcxprograms.yaml index 88074f1b7..22d26f1d6 100644 --- a/config/crd/bases/bpfman.io_tcxprograms.yaml +++ b/config/crd/bases/bpfman.io_tcxprograms.yaml @@ -182,10 +182,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -345,10 +341,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/crd/bases/bpfman.io_tracepointprograms.yaml b/config/crd/bases/bpfman.io_tracepointprograms.yaml index dcc2d40b1..20aee0e47 100644 --- a/config/crd/bases/bpfman.io_tracepointprograms.yaml +++ b/config/crd/bases/bpfman.io_tracepointprograms.yaml @@ -70,10 +70,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -233,10 +229,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/crd/bases/bpfman.io_uprobensprograms.yaml b/config/crd/bases/bpfman.io_uprobensprograms.yaml index 5077d3801..8c4da41fd 100644 --- a/config/crd/bases/bpfman.io_uprobensprograms.yaml +++ b/config/crd/bases/bpfman.io_uprobensprograms.yaml @@ -173,10 +173,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -336,10 +332,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/crd/bases/bpfman.io_uprobeprograms.yaml b/config/crd/bases/bpfman.io_uprobeprograms.yaml index 0bafdd660..ccd1acced 100644 --- a/config/crd/bases/bpfman.io_uprobeprograms.yaml +++ b/config/crd/bases/bpfman.io_uprobeprograms.yaml @@ -176,10 +176,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -339,10 +335,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/crd/bases/bpfman.io_xdpnsprograms.yaml b/config/crd/bases/bpfman.io_xdpnsprograms.yaml index 9a0cf2f5e..5b63d021a 100644 --- a/config/crd/bases/bpfman.io_xdpnsprograms.yaml +++ b/config/crd/bases/bpfman.io_xdpnsprograms.yaml @@ -183,10 +183,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -346,10 +342,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/crd/bases/bpfman.io_xdpprograms.yaml b/config/crd/bases/bpfman.io_xdpprograms.yaml index 1c3e9d23f..0ff37349c 100644 --- a/config/crd/bases/bpfman.io_xdpprograms.yaml +++ b/config/crd/bases/bpfman.io_xdpprograms.yaml @@ -170,6 +170,9 @@ spec: 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 @@ -188,10 +191,6 @@ spec: type: array bpffunctionname: description: |- - ANF-TODO: BpfProgramCommon is deprecated and will be removed. - MapOwnerSelector has been moved to BpfAppCommon and BpfFunctionName is the - key for the Programs list in the BpfApplicationSpec. Do not use in new - load/attach split code. BpfFunctionName is the name of the function that is the entry point for the BPF program type: string @@ -351,10 +350,14 @@ spec: x-kubernetes-map-type: atomic oldmapownerselector: description: |- - 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. + 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. diff --git a/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml b/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml index d60fba24a..713a9cf4c 100644 --- a/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml +++ b/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml @@ -31,7 +31,7 @@ spec: # primarynodeinterface: true # priority: 55 # direction: ingress - tcx_stats: + - bpffunctionname: tcx_next type: TCX tcx: bpffunctionname: tcx_next @@ -40,6 +40,19 @@ spec: 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 @@ -55,7 +68,7 @@ spec: # containernames: # - bpfman # - bpfman-agent - xdp_stats: + - bpffunctionname: xdp_pass type: XDP xdp: bpffunctionname: xdp_pass @@ -64,7 +77,8 @@ spec: primarynodeinterface: true priority: 55 - interfaceselector: - primarynodeinterface: true + interfaces: + - eth0 priority: 100 containers: namespace: bpfman @@ -74,7 +88,7 @@ spec: containernames: - bpfman - bpfman-agent - test_fentry: + - bpffunctionname: fentry_test type: Fentry fentry: bpffunctionname: fentry_test diff --git a/controllers/app-agent/cl-application-program.go b/controllers/app-agent/cl-application-program.go index e551891a8..a45a451b6 100644 --- a/controllers/app-agent/cl-application-program.go +++ b/controllers/app-agent/cl-application-program.go @@ -24,6 +24,7 @@ import ( 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" @@ -116,30 +117,28 @@ func (r *BpfApplicationReconciler) SetupWithManager(mgr ctrl.Manager) error { } func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - r.Logger.Info("Enter BpfApplication Reconcile", "Name", req.Name) - // Initialize node and current program - r.currentApp = &bpfmaniov1alpha1.BpfApplication{} + // 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 @@ -161,11 +160,12 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque // 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. - bpfAppState, bpfAppStateNew, err := r.getBpfAppState(ctx, true) + 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 @@ -175,16 +175,13 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque // created anyway. var bpfAppStateOriginal *bpfmaniov1alpha1.BpfApplicationState if !bpfAppStateNew { - bpfAppStateOriginal = bpfAppState.DeepCopy() + bpfAppStateOriginal = r.currentAppState.DeepCopy() } r.Logger.Info("From getBpfAppState", "new", bpfAppStateNew) - r.currentAppState = bpfAppState - - r.Logger.Info("Calling reconcileLoad()") - // 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 @@ -205,10 +202,12 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque // to Error if any of the programs have an error. bpfApplicationStatus := bpfmaniov1alpha1.ProgramReconcileSuccess + // function + // Reconcile each program in the BpfApplication - for progName, prog := range a.Spec.Programs { - progState, ok := bpfAppState.Spec.Programs[progName] - if !ok { + 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. @@ -219,8 +218,8 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque // 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("XdpProgramState not found"), - "XdpProgramState not found", "App Name", r.currentApp.Name, "Program Name", progName) + r.Logger.Error(fmt.Errorf("ProgramState not found"), + "ProgramState not found", "App Name", r.currentApp.Name, "BpfFunctionName", prog.BpfFunctionName) continue } @@ -233,7 +232,7 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque ProgramReconcilerCommon: ProgramReconcilerCommon{ appCommon: r.currentApp.Spec.BpfAppCommon, currentProgram: &prog, - currentProgramState: &progState, + currentProgramState: progState, }, } err = rec.reconcileProgram(ctx, rec, r.isBeingDeleted()) @@ -250,7 +249,7 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque ProgramReconcilerCommon: ProgramReconcilerCommon{ appCommon: r.currentApp.Spec.BpfAppCommon, currentProgram: &prog, - currentProgramState: &progState, + currentProgramState: progState, }, } err = rec.reconcileProgram(ctx, rec, r.isBeingDeleted()) @@ -261,7 +260,7 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque ProgramReconcilerCommon: ProgramReconcilerCommon{ appCommon: r.currentApp.Spec.BpfAppCommon, currentProgram: &prog, - currentProgramState: &progState, + currentProgramState: progState, }, } err = rec.reconcileProgram(ctx, rec, r.isBeingDeleted()) @@ -276,14 +275,12 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque if err != nil { progState.ProgramAttachStatus = bpfmaniov1alpha1.BpfProgCondAttachError bpfApplicationStatus = bpfmaniov1alpha1.ProgramReconcileError - r.Logger.Error(err, "reconcile failure", "App Name", r.currentApp.Name, "Program Name", progName, "Type", prog.Type) + 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, "Program Name", progName, "Type", prog.Type) + r.Logger.Info("reconcile success", "App Name", r.currentApp.Name, "BpfFunctionName", prog.BpfFunctionName, "Type", prog.Type) } - bpfAppState.Spec.Programs[progName] = progState - r.Logger.Info("Done reconciling program", "Application", i, "Name", r.currentAppState.GetName()) } @@ -323,6 +320,29 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque 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 @@ -444,9 +464,10 @@ func (r *BpfApplicationReconciler) createBpfAppState() (*bpfmaniov1alpha1.BpfApp }, }, Spec: bpfmaniov1alpha1.BpfApplicationStateSpec{ + Node: r.NodeName, AppLoadStatus: bpfmaniov1alpha1.BpfProgCondNotLoaded, UpdateCount: 0, - Programs: map[string]bpfmaniov1alpha1.BpfApplicationProgramState{}, + Programs: []bpfmaniov1alpha1.BpfApplicationProgramState{}, }, Status: bpfmaniov1alpha1.BpfAppStatus{Conditions: []metav1.Condition{}}, } @@ -465,17 +486,40 @@ func (r *BpfApplicationReconciler) createBpfAppState() (*bpfmaniov1alpha1.BpfApp } 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 progName, prog := range r.currentApp.Spec.Programs { + 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{} + 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: @@ -485,7 +529,9 @@ func (r *BpfApplicationReconciler) initializeNodeProgramList(bpfAppState *bpfman case bpfmaniov1alpha1.ProgTypeTC: panic(fmt.Sprintf("%v not implemented yet", prog.Type)) case bpfmaniov1alpha1.ProgTypeTCX: - progState.TCX = &bpfmaniov1alpha1.TcxProgramInfoState{} + progState.TCX = &bpfmaniov1alpha1.TcxProgramInfoState{ + AttachPoints: []bpfmaniov1alpha1.TcxAttachInfoState{}, + } case bpfmaniov1alpha1.ProgTypeTracepoint: panic(fmt.Sprintf("%v not implemented yet", prog.Type)) case bpfmaniov1alpha1.ProgTypeUprobe: @@ -493,12 +539,14 @@ func (r *BpfApplicationReconciler) initializeNodeProgramList(bpfAppState *bpfman case bpfmaniov1alpha1.ProgTypeUretprobe: panic(fmt.Sprintf("%v not implemented yet", prog.Type)) case bpfmaniov1alpha1.ProgTypeXDP: - progState.XDP = &bpfmaniov1alpha1.XdpProgramInfoState{} + progState.XDP = &bpfmaniov1alpha1.XdpProgramInfoState{ + AttachPoints: []bpfmaniov1alpha1.XdpAttachInfoState{}, + } default: - panic(fmt.Sprintf("unexpected v1alpha1.EBPFProgType: %#v", prog.Type)) + panic(fmt.Sprintf("unexpected EBPFProgType: %#v", prog.Type)) } - bpfAppState.Spec.Programs[progName] = progState + 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 index d7a8ac782..f1aaa89d2 100644 --- a/controllers/app-agent/cl-application-program_test.go +++ b/controllers/app-agent/cl-application-program_test.go @@ -30,6 +30,7 @@ func TestBpfApplicationControllerCreate(t *testing.T) { xdpBpfFunctionName = "XdpTest" tcxBpfFunctionName = "TcxTest" fentryBpfFunctionName = "FentryTest" + fentryAttachFunction = "FentryAttachTest" priority = 50 fakeNode = testutils.NewNode("fake-control-plane") fakeInt0 = "eth0" @@ -45,6 +46,8 @@ func TestBpfApplicationControllerCreate(t *testing.T) { // fakeUID1 = "ef71d42c-aa21-48e8-a697-82391d801a81" ) + programs := []bpfmaniov1alpha1.BpfApplicationProgram{} + fakeInts := []string{fakeInt0} interfaceSelector := bpfmaniov1alpha1.InterfaceSelector{ @@ -61,48 +64,50 @@ func TestBpfApplicationControllerCreate(t *testing.T) { ProceedOn: proceedOn, } - // A AppProgram object with metadata and spec. - programMap := make(map[string]bpfmaniov1alpha1.BpfApplicationProgram) - - programMap[xdpBpfFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + xdpProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: xdpBpfFunctionName, + }, Type: bpfmaniov1alpha1.ProgTypeXDP, XDP: &bpfmaniov1alpha1.XdpProgramInfo{ - BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ - BpfFunctionName: xdpBpfFunctionName, - OldMapOwnerSelector: metav1.LabelSelector{}, - }, AttachPoints: []bpfmaniov1alpha1.XdpAttachInfo{xdpAttachInfo}, }, } + programs = append(programs, xdpProgram) + tcxAttachInfo := bpfmaniov1alpha1.TcxAttachInfo{ InterfaceSelector: interfaceSelector, Containers: nil, Direction: "ingress", Priority: int32(priority), } - - programMap[tcxBpfFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + tcProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: tcxBpfFunctionName, + }, Type: bpfmaniov1alpha1.ProgTypeTCX, TCX: &bpfmaniov1alpha1.TcxProgramInfo{ - BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ - BpfFunctionName: tcxBpfFunctionName, - OldMapOwnerSelector: metav1.LabelSelector{}, - }, AttachPoints: []bpfmaniov1alpha1.TcxAttachInfo{tcxAttachInfo}, }, } + programs = append(programs, tcProgram) - programMap[fentryBpfFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + fentryProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: fentryBpfFunctionName, + }, Type: bpfmaniov1alpha1.ProgTypeFentry, Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ - BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ - BpfFunctionName: fentryBpfFunctionName, - OldMapOwnerSelector: metav1.LabelSelector{}, + FentryLoadInfo: bpfmaniov1alpha1.FentryLoadInfo{ + FunctionName: fentryAttachFunction, + }, + FentryAttachInfo: bpfmaniov1alpha1.FentryAttachInfo{ + Attach: true, }, - FentryAttachInfo: bpfmaniov1alpha1.FentryAttachInfo{Attach: true}, }, } + programs = append(programs, fentryProgram) bpfApp := &bpfmaniov1alpha1.BpfApplication{ ObjectMeta: metav1.ObjectMeta{ @@ -115,7 +120,7 @@ func TestBpfApplicationControllerCreate(t *testing.T) { Path: &bytecodePath, }, }, - Programs: programMap, + Programs: programs, }, } @@ -208,9 +213,9 @@ func TestBpfApplicationControllerCreate(t *testing.T) { // Check that the bpfAppState was not updated require.True(t, reflect.DeepEqual(bpfAppState, bpfAppState2)) - currentProgram := programMap[xdpBpfFunctionName] + currentXdpProgram := programs[0] - attachPoint := bpfAppState2.Spec.Programs[xdpBpfFunctionName].XDP.AttachPoints[0] + attachPoint := bpfAppState2.Spec.Programs[0].XDP.AttachPoints[0] xdpReconciler := &XdpProgramReconciler{ ReconcilerCommon: rc, @@ -221,7 +226,7 @@ func TestBpfApplicationControllerCreate(t *testing.T) { Path: &bytecodePath, }, }, - currentProgram: ¤tProgram, + currentProgram: ¤tXdpProgram, currentProgramState: &bpfmaniov1alpha1.BpfApplicationProgramState{}, }, currentAttachPoint: &attachPoint, diff --git a/controllers/app-agent/cl-fentry-program.go b/controllers/app-agent/cl-fentry-program.go index e38a42736..c7ccb1bb8 100644 --- a/controllers/app-agent/cl-fentry-program.go +++ b/controllers/app-agent/cl-fentry-program.go @@ -26,7 +26,6 @@ import ( 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" ) @@ -37,9 +36,6 @@ import ( type FentryProgramReconciler struct { ReconcilerCommon ProgramReconcilerCommon - // ANF-TODO: appCommon is needed to load the program. It won't be needed - // after the load/attch split is ready. - currentAttachPoint *bpfmaniov1alpha1.FentryAttachInfoState } func (r *FentryProgramReconciler) getProgId() *uint32 { @@ -59,41 +55,50 @@ func (r *FentryProgramReconciler) getBpfGlobalData() map[string][]byte { } func (r *FentryProgramReconciler) shouldAttach() bool { - return r.currentAttachPoint.ShouldAttach + return r.currentProgramState.Fentry.ShouldAttach } func (r *FentryProgramReconciler) getUUID() string { - return r.currentAttachPoint.UUID + return r.currentProgramState.Fentry.UUID } func (r *FentryProgramReconciler) getAttachId() *uint32 { - return r.currentAttachPoint.AttachId + return r.currentProgramState.Fentry.AttachId } func (r *FentryProgramReconciler) setAttachId(id *uint32) { - r.currentAttachPoint.AttachId = id + r.currentProgramState.Fentry.AttachId = id } func (r *FentryProgramReconciler) setAttachStatus(status bpfmaniov1alpha1.BpfProgramConditionType) bool { - return updateSimpleStatus(&r.currentAttachPoint.AttachStatus, status) + return updateSimpleStatus(&r.currentProgramState.Fentry.AttachStatus, status) } func (r *FentryProgramReconciler) getAttachStatus() bpfmaniov1alpha1.BpfProgramConditionType { - return r.currentAttachPoint.AttachStatus + return r.currentProgramState.Fentry.AttachStatus } func (r *FentryProgramReconciler) getLoadRequest(mapOwnerId *uint32) (*gobpfman.LoadRequest, error) { - r.Logger.Info("Getting load request", "bpfFunctionName", r.currentProgram.Fentry.BpfFunctionName, "reqAttachInfo", r.currentAttachPoint, "mapOwnerId", - mapOwnerId, "ByteCode", r.appCommon.ByteCode) + 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: r.currentProgram.Fentry.BpfFunctionName, + Name: bpfFunctionName, ProgramType: uint32(internal.Tracing), Attach: &gobpfman.AttachInfo{ Info: &gobpfman.AttachInfo_FentryAttachInfo{ @@ -102,7 +107,8 @@ func (r *FentryProgramReconciler) getLoadRequest(mapOwnerId *uint32) (*gobpfman. }, }, }, - Metadata: map[string]string{internal.UuidMetadataKey: string(r.currentAttachPoint.UUID), internal.ProgramNameKey: "BpfApplication"}, + Metadata: map[string]string{internal.UuidMetadataKey: string(r.currentProgramState.Fentry.UUID), + internal.ProgramNameKey: "BpfApplication"}, GlobalData: r.appCommon.GlobalData, MapOwnerId: mapOwnerId, } @@ -115,14 +121,6 @@ func (r *FentryProgramReconciler) getLoadRequest(mapOwnerId *uint32) (*gobpfman. func (r *FentryProgramReconciler) updateAttachInfo(ctx context.Context, isBeingDeleted bool) error { r.Logger.Info("Fentry 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.Fentry.AttachPoints { - r.Logger.Info("Setting ShouldAttach to false", "index", i) - r.currentProgramState.Fentry.AttachPoints[i].ShouldAttach = false - } - if isBeingDeleted { // If the program is being deleted, we don't need to do anything else. // @@ -130,51 +128,16 @@ func (r *FentryProgramReconciler) updateAttachInfo(ctx context.Context, isBeingD // 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 - } - // ANF-TODO: Fentry and Fexit just have a single attach point, so we don't - // have to do a loop here. This makes them different from most of the other - // program types, so we'd have to handle this if we try to make this - // function common. - expectedAttachPoints, error := r.getExpectedAttachPoints(ctx, r.currentProgram.Fentry.FentryAttachInfo) - 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.Fentry.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.Fentry.AttachPoints = append(r.currentProgramState.Fentry.AttachPoints, attachPoint) - } + r.currentProgramState.Fentry.ShouldAttach = false + return nil } - // 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. + r.currentProgramState.Fentry.ShouldAttach = r.currentProgram.Fentry.Attach 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 *FentryProgramReconciler) findAttachPoint(attachInfoState bpfmaniov1alpha1.FentryAttachInfoState) *int { - for i, a := range r.currentProgramState.Fentry.AttachPoints { - // attachInfoState is the same as a if the the following fields are the - // same: FunctionName. - if a.FunctionName == attachInfoState.FunctionName { - 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 @@ -193,35 +156,9 @@ func (r *FentryProgramReconciler) processAttachInfo(ctx context.Context, mapOwne 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.Fentry.AttachPoints { - r.currentAttachPoint = &r.currentProgramState.Fentry.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.Fentry.AttachPoints = r.removeAttachPoints(r.currentProgramState.Fentry.AttachPoints, attachPointsToRemove) - } + _, err = r.reconcileBpfAttachment(ctx, r, loadedBpfPrograms, mapOwnerStatus) - return lastReconcileAttachmentError + return err } // removeAttachPoints removes attach points from a slice of attach points based on the keys in the map. @@ -235,22 +172,21 @@ func (r *FentryProgramReconciler) removeAttachPoints(attachPoints []bpfmaniov1al 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, - }, - FunctionName: r.currentProgram.Fentry.FunctionName, - } - attachPoints = append(attachPoints, attachPoint) - } - - return attachPoints, nil -} +// // 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 index b850d7e94..c27d72416 100644 --- a/controllers/app-agent/cl-tcx-program.go +++ b/controllers/app-agent/cl-tcx-program.go @@ -83,7 +83,7 @@ func (r *TcxProgramReconciler) getAttachStatus() bpfmaniov1alpha1.BpfProgramCond func (r *TcxProgramReconciler) getLoadRequest(mapOwnerId *uint32) (*gobpfman.LoadRequest, error) { - r.Logger.Info("Getting load request", "bpfFunctionName", r.currentProgram.TCX.BpfFunctionName, "reqAttachInfo", r.currentAttachPoint, "mapOwnerId", + 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) @@ -102,9 +102,19 @@ func (r *TcxProgramReconciler) getLoadRequest(mapOwnerId *uint32) (*gobpfman.Loa 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, - Name: r.currentProgram.TCX.BpfFunctionName, + Bytecode: bytecode, + // ANF-TODO: Name should come from + Name: bpfFunctionName, ProgramType: uint32(internal.Tc), Attach: &gobpfman.AttachInfo{ Info: &gobpfman.AttachInfo_TcxAttachInfo{ diff --git a/controllers/app-agent/cl-xdp-program.go b/controllers/app-agent/cl-xdp-program.go index afe31c86c..d339d90e1 100644 --- a/controllers/app-agent/cl-xdp-program.go +++ b/controllers/app-agent/cl-xdp-program.go @@ -107,7 +107,7 @@ func xdpProceedOnToInt(proceedOn []bpfmaniov1alpha1.XdpProceedOnValue) []int32 { func (r *XdpProgramReconciler) getLoadRequest(mapOwnerId *uint32) (*gobpfman.LoadRequest, error) { - r.Logger.Info("Getting load request", "bpfFunctionName", r.currentProgram.XDP.BpfFunctionName, "reqAttachInfo", r.currentAttachPoint, "mapOwnerId", + 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) @@ -126,9 +126,18 @@ func (r *XdpProgramReconciler) getLoadRequest(mapOwnerId *uint32) (*gobpfman.Loa 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: r.currentProgram.XDP.BpfFunctionName, + Name: bpfFunctionName, ProgramType: uint32(internal.Xdp), Attach: &gobpfman.AttachInfo{ Info: &gobpfman.AttachInfo_XdpAttachInfo{ diff --git a/controllers/app-agent/common.go b/controllers/app-agent/common.go index bbf733783..31e8dcaa5 100644 --- a/controllers/app-agent/common.go +++ b/controllers/app-agent/common.go @@ -126,7 +126,7 @@ func (r *ReconcilerCommon) reconcileLoad(rec ApplicationReconciler) error { // 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 + // 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 diff --git a/controllers/app-operator/application-cl-program_test.go b/controllers/app-operator/application-cl-program_test.go index 75363cb18..06c376add 100644 --- a/controllers/app-operator/application-cl-program_test.go +++ b/controllers/app-operator/application-cl-program_test.go @@ -76,20 +76,20 @@ func appProgramReconcile(t *testing.T, multiCondition bool) { ProceedOn: proceedOn, } - // A AppProgram object with metadata and spec. - programMap := make(map[string]bpfmaniov1alpha1.BpfApplicationProgram) + programs := []bpfmaniov1alpha1.BpfApplicationProgram{} - programMap[xdpBpfFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + xdpProgram := bpfmaniov1alpha1.BpfApplicationProgram{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: xdpBpfFunctionName, + }, Type: bpfmaniov1alpha1.ProgTypeXDP, XDP: &bpfmaniov1alpha1.XdpProgramInfo{ - BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ - BpfFunctionName: xdpBpfFunctionName, - OldMapOwnerSelector: metav1.LabelSelector{}, - }, AttachPoints: []bpfmaniov1alpha1.XdpAttachInfo{attachInfo}, }, } + programs = append(programs, xdpProgram) + // programMap[bpfFentryFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ // Type: bpfmaniov1alpha1.ProgTypeFentry, // Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ @@ -142,7 +142,7 @@ func appProgramReconcile(t *testing.T, multiCondition bool) { Path: &bytecodePath, }, }, - Programs: programMap, + Programs: programs, }, } @@ -161,7 +161,7 @@ func appProgramReconcile(t *testing.T, multiCondition bool) { }, Spec: bpfmaniov1alpha1.BpfApplicationStateSpec{ AppLoadStatus: bpfmaniov1alpha1.BpfProgCondLoaded, - Programs: map[string]bpfmaniov1alpha1.BpfApplicationProgramState{}, + Programs: []bpfmaniov1alpha1.BpfApplicationProgramState{}, }, Status: bpfmaniov1alpha1.BpfAppStatus{ Conditions: []metav1.Condition{bpfmaniov1alpha1.ProgramReconcileSuccess.Condition("")}, diff --git a/controllers/bpfman-agent/application-program_test.go b/controllers/bpfman-agent/application-program_test.go index 49398cf18..41a50d9de 100644 --- a/controllers/bpfman-agent/application-program_test.go +++ b/controllers/bpfman-agent/application-program_test.go @@ -51,10 +51,9 @@ func TestBpfApplicationControllerCreate(t *testing.T) { kprobecontainerpid int32 = 0 ) - // A AppProgram object with metadata and spec. - programMap := make(map[string]bpfmaniov1alpha1.BpfApplicationProgram) + programs := []bpfmaniov1alpha1.BpfApplicationProgram{} - programMap[bpfFentryFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + fentryProgram := bpfmaniov1alpha1.BpfApplicationProgram{ Type: bpfmaniov1alpha1.ProgTypeFentry, Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ @@ -65,7 +64,9 @@ func TestBpfApplicationControllerCreate(t *testing.T) { }, } - programMap[bpfKprobeFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + programs = append(programs, fentryProgram) + + kprobeProgram := bpfmaniov1alpha1.BpfApplicationProgram{ Type: bpfmaniov1alpha1.ProgTypeKprobe, Kprobe: &bpfmaniov1alpha1.KprobeProgramInfo{ BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ @@ -81,6 +82,8 @@ func TestBpfApplicationControllerCreate(t *testing.T) { }, } + programs = append(programs, kprobeProgram) + App := &bpfmaniov1alpha1.BpfApplication{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -92,7 +95,7 @@ func TestBpfApplicationControllerCreate(t *testing.T) { Path: &bytecodePath, }, }, - Programs: programMap, + Programs: programs, }, } diff --git a/controllers/bpfman-operator/application-program_test.go b/controllers/bpfman-operator/application-program_test.go index e604cef8e..80b4001f4 100644 --- a/controllers/bpfman-operator/application-program_test.go +++ b/controllers/bpfman-operator/application-program_test.go @@ -59,9 +59,9 @@ func appProgramReconcile(t *testing.T, multiCondition bool) { // A AppProgram object with metadata and spec. - programMap := make(map[string]bpfmaniov1alpha1.BpfApplicationProgram) + programs := []bpfmaniov1alpha1.BpfApplicationProgram{} - programMap[bpfFentryFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + fentryProgram := bpfmaniov1alpha1.BpfApplicationProgram{ Type: bpfmaniov1alpha1.ProgTypeFentry, Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ @@ -72,7 +72,9 @@ func appProgramReconcile(t *testing.T, multiCondition bool) { }, } - programMap[bpfKprobeFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + programs = append(programs, fentryProgram) + + kprobeProgram := bpfmaniov1alpha1.BpfApplicationProgram{ Type: bpfmaniov1alpha1.ProgTypeKprobe, Kprobe: &bpfmaniov1alpha1.KprobeProgramInfo{ BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ @@ -88,7 +90,9 @@ func appProgramReconcile(t *testing.T, multiCondition bool) { }, } - programMap[bpfTracepointFunctionName] = bpfmaniov1alpha1.BpfApplicationProgram{ + programs = append(programs, kprobeProgram) + + tracePointProgram := bpfmaniov1alpha1.BpfApplicationProgram{ Type: bpfmaniov1alpha1.ProgTypeTracepoint, Tracepoint: &bpfmaniov1alpha1.TracepointProgramInfo{ BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ @@ -102,6 +106,8 @@ func appProgramReconcile(t *testing.T, multiCondition bool) { }, } + programs = append(programs, tracePointProgram) + App := &bpfmaniov1alpha1.BpfApplication{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -113,7 +119,7 @@ func appProgramReconcile(t *testing.T, multiCondition bool) { Path: &bytecodePath, }, }, - Programs: programMap, + Programs: programs, }, }