From 2799666c15304cb94a44e6481bcb7ec6d8bcdb58 Mon Sep 17 00:00:00 2001 From: Andre Fredette Date: Mon, 9 Dec 2024 18:44:14 -0500 Subject: [PATCH] Support for Load/Attach Split with Initial Cluster-Scoped XDP 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 `BpfApplicationNode` CRD to manage per-node information for a single `BpfApplication`. - Proof of concept and initial implementation for cluster-scoped XDP programs, with working unit tests in the app-agent. Additionally: - Updated existing controllers to work with the new CRD format, though currently limited to XDP programs. - Initial changes in the operator to support the load/attach split, with further cleanup and support for additional program types planned. TODO: - Generalize the agent code to support multiple program types. - Support for namespace-scoped CRDs and other program types beyond XDP. - More clean-up, complete testing, and address remaining edge cases. Signed-off-by: Andre Fredette --- Makefile | 4 +- PROJECT | 7 + apis/v1alpha1/bpfApplicationNode_types.go | 172 ++ apis/v1alpha1/bpfApplication_types.go | 19 +- apis/v1alpha1/bpfNsApplication_types.go | 2 +- apis/v1alpha1/fentryProgram_types.go | 39 +- apis/v1alpha1/fexitProgram_types.go | 21 +- 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 | 16 +- 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 | 44 +- apis/v1alpha1/zz_generated.deepcopy.go | 660 ++++++-- 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 | 94 +- .../bpfman.io_bpfapplicationnodes.yaml | 428 +++++ .../manifests/bpfman.io_bpfapplications.yaml | 1385 ++++++++++------- .../bpfman.io_bpfnsapplications.yaml | 1165 +++++++------- .../manifests/bpfman.io_fentryprograms.yaml | 75 +- bundle/manifests/bpfman.io_fexitprograms.yaml | 75 +- .../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 | 280 ++-- .../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 | 292 ++-- cmd/bpfman-agent/main.go | 243 +-- cmd/bpfman-operator/main.go | 220 +-- config/bpfman-deployment/config.yaml | 2 +- .../bases/bpfman.io_bpfapplicationnodes.yaml | 422 +++++ .../crd/bases/bpfman.io_bpfapplications.yaml | 1385 ++++++++++------- .../bases/bpfman.io_bpfnsapplications.yaml | 1165 +++++++------- .../crd/bases/bpfman.io_fentryprograms.yaml | 75 +- config/crd/bases/bpfman.io_fexitprograms.yaml | 75 +- .../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 | 280 ++-- .../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 | 292 ++-- 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 | 92 +- controllers/app-agent/application-common.go | 515 ++++++ controllers/app-agent/application-program.go | 469 ++++++ .../app-agent/application-program_test.go | 384 +++++ controllers/app-agent/containers.go | 252 +++ 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/xdp-program.go | 358 +++++ .../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 +- .../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 | 1 + internal/k8s.go | 4 +- .../apis/v1alpha1/bpfapplicationnode.go | 68 + .../apis/v1alpha1/expansion_generated.go | 4 + .../typed/apis/v1alpha1/apis_client.go | 5 + .../typed/apis/v1alpha1/bpfapplicationnode.go | 184 +++ .../apis/v1alpha1/fake/fake_apis_client.go | 4 + .../v1alpha1/fake/fake_bpfapplicationnode.go | 132 ++ .../apis/v1alpha1/generated_expansion.go | 2 + .../apis/v1alpha1/bpfapplicationnode.go | 89 ++ .../apis/v1alpha1/interface.go | 7 + pkg/client/externalversions/generic.go | 2 + pkg/helpers/helpers.go | 20 + 133 files changed, 13579 insertions(+), 5034 deletions(-) create mode 100644 apis/v1alpha1/bpfApplicationNode_types.go create mode 100644 bundle/manifests/bpfman.io_bpfapplicationnodes.yaml create mode 100644 config/crd/bases/bpfman.io_bpfapplicationnodes.yaml create mode 100644 controllers/app-agent/application-common.go 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/containers.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/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/bpfapplicationnode.go create mode 100644 pkg/client/clientset/typed/apis/v1alpha1/bpfapplicationnode.go create mode 100644 pkg/client/clientset/typed/apis/v1alpha1/fake/fake_bpfapplicationnode.go create mode 100644 pkg/client/externalversions/apis/v1alpha1/bpfapplicationnode.go diff --git a/Makefile b/Makefile index 4bc6185c7..512d2cfec 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..f2ee9e88a 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: BpfApplicationNode + path: github.com/bpfman/bpfman-operator/apis/v1alpha1 + version: v1alpha1 version: "3" diff --git a/apis/v1alpha1/bpfApplicationNode_types.go b/apis/v1alpha1/bpfApplicationNode_types.go new file mode 100644 index 000000000..5553b1695 --- /dev/null +++ b/apis/v1alpha1/bpfApplicationNode_types.go @@ -0,0 +1,172 @@ +/* +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" +) + +// BpfApplicationProgramNode 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 BpfApplicationProgramNode 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 *XdpProgramInfoNode `json:"xdp,omitempty"` + + // tc defines the desired state of the application's TcPrograms. + // +unionMember + // +optional + TC *TcProgramInfoNode `json:"tc,omitempty"` + + // // tcx defines the desired state of the application's TcxPrograms. + // // +unionMember + // // +optional + // TCX *TcxProgramInfoNode `json:"tcx,omitempty"` + + // fentry defines the desired state of the application's FentryPrograms. + // +unionMember + // +optional + Fentry *FentryProgramInfoNode `json:"fentry,omitempty"` + + // // fexit defines the desired state of the application's FexitPrograms. + // // +unionMember + // // +optional + // Fexit *FexitProgramInfoNode `json:"fexit,omitempty"` + + // // kprobe defines the desired state of the application's KprobePrograms. + // // +unionMember + // // +optional + // Kprobe *KprobeProgramInfoNode `json:"kprobe,omitempty"` + + // // kretprobe defines the desired state of the application's KretprobePrograms. + // // +unionMember + // // +optional + // Kretprobe *KprobeProgramInfoNode `json:"kretprobe,omitempty"` + + // // uprobe defines the desired state of the application's UprobePrograms. + // // +unionMember + // // +optional + // Uprobe *UprobeProgramInfoNode `json:"uprobe,omitempty"` + + // // uretprobe defines the desired state of the application's UretprobePrograms. + // // +unionMember + // // +optional + // Uretprobe *UprobeProgramInfoNode `json:"uretprobe,omitempty"` + + // // tracepoint defines the desired state of the application's TracepointPrograms. + // // +unionMember + // // +optional + // Tracepoint *TracepointProgramInfoNode `json:"tracepoint,omitempty"` +} + +// BpfApplicationSpec defines the desired state of BpfApplication +type BpfApplicationNodeSpec struct { + // The number of times the BpfApplicationNode 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 BpfApplicationProgramNode + // elements. + Programs map[string]BpfApplicationProgramNode `json:"programs,omitempty"` +} + +// +genclient +// +genclient:nonNamespaced +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// BpfApplicationNode is the Schema for the bpfapplications API +// +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 BpfApplicationNode struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec BpfApplicationNodeSpec `json:"spec,omitempty"` + Status BpfAppStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +// BpfApplicationList contains a list of BpfApplications +type BpfApplicationNodeList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []BpfApplicationNode `json:"items"` +} + +func (an BpfApplicationNode) GetName() string { + return an.Name +} + +func (an BpfApplicationNode) GetUID() metav1types.UID { + return an.UID +} + +func (an BpfApplicationNode) GetAnnotations() map[string]string { + return an.Annotations +} + +func (an BpfApplicationNode) GetLabels() map[string]string { + return an.Labels +} + +func (an BpfApplicationNode) GetStatus() *BpfAppStatus { + return &an.Status +} + +func (an BpfApplicationNode) GetClientObject() client.Object { + return &an +} + +func (anl BpfApplicationNodeList) GetItems() []BpfApplicationNode { + 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..8c6d0dadc 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,19 @@ 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 + // +kubebuilder:default=false + Attach bool `json:"attach"` } -// 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"` } // +kubebuilder:object:root=true @@ -68,3 +73,21 @@ type FentryProgramList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []FentryProgram `json:"items"` } + +type FentryProgramInfoNode struct { + // The list of points to which the program should be attached. + // FentryAttachInfoNode is similar to FentryAttachInfo, but the interface and + // container selectors are expanded, and we have one instance of + // FentryAttachInfoNode for each unique attach point. The list is optional and + // may be udated after the bpf program has been loaded. + // +optional + AttachPoint FentryAttachInfoNode `json:"attach_points"` +} + +type FentryAttachInfoNode 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"` +} diff --git a/apis/v1alpha1/fexitProgram_types.go b/apis/v1alpha1/fexitProgram_types.go index 97467996e..f078500f1 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,19 @@ 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 + // +kubebuilder:default=false + Attach bool `json:"attach"` } -// FexitProgramStatus defines the observed state of FexitProgram -type FexitProgramStatus struct { - BpfProgramStatusCommon `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"` } // +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..672fa3b69 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 BpfApplicationNode object +type BpfAppStatus struct { + // For a BpfApplication object, Conditions contains the global cluster state + // for the object. For a BpfApplicationNode 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..efd7752e0 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 TcProgramInfoNode struct { + // The list of points to which the program should be attached. + // TcAttachInfoNode is similar to TcAttachInfo, but the interface and + // container selectors are expanded, and we have one instance of + // TcAttachInfoNode for each unique attach point. The list is optional and + // may be udated after the bpf program has been loaded. + // +optional + AttachPoints []TcAttachInfoNode `json:"attach_points"` +} + +type TcAttachInfoNode 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..4022c2d5c 100644 --- a/apis/v1alpha1/tcxProgram_types.go +++ b/apis/v1alpha1/tcxProgram_types.go @@ -40,9 +40,8 @@ type TcxProgram struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec TcxProgramSpec `json:"spec"` - // +optional - Status TcxProgramStatus `json:"status,omitempty"` + Spec TcxProgramSpec `json:"spec"` + Status BpfAppStatus `json:"status,omitempty"` } // TcxProgramSpec defines the desired state of TcxProgram @@ -54,7 +53,13 @@ type TcxProgramSpec struct { // TcxProgramInfo defines the tc 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"` @@ -77,11 +82,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 { 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..119d44b49 100644 --- a/apis/v1alpha1/xdpProgram_types.go +++ b/apis/v1alpha1/xdpProgram_types.go @@ -41,7 +41,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 @@ -56,6 +56,13 @@ type XdpProgramSpec struct { // XdpProgramInfo defines the common fields for all XdpProgram types 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 +90,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 +100,36 @@ type XdpProgramList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []XdpProgram `json:"items"` } + +type XdpProgramInfoNode struct { + // The list of points to which the program should be attached. + // XdpAttachInfoNode is similar to XdpAttachInfo, but the interface and + // container selectors are expanded, and we have one instance of + // XdpAttachInfoNode for each unique attach point. The list is optional and + // may be udated after the bpf program has been loaded. + // +optional + AttachPoints []XdpAttachInfoNode `json:"attach_points"` +} + +type XdpAttachInfoNode 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..cd26b82aa 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 @@ -117,6 +164,87 @@ func (in *BpfApplicationList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BpfApplicationNode) DeepCopyInto(out *BpfApplicationNode) { + *out = *in + 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 BpfApplicationNode. +func (in *BpfApplicationNode) DeepCopy() *BpfApplicationNode { + if in == nil { + return nil + } + out := new(BpfApplicationNode) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BpfApplicationNode) 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 *BpfApplicationNodeList) DeepCopyInto(out *BpfApplicationNodeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]BpfApplicationNode, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfApplicationNodeList. +func (in *BpfApplicationNodeList) DeepCopy() *BpfApplicationNodeList { + if in == nil { + return nil + } + out := new(BpfApplicationNodeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BpfApplicationNodeList) 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 *BpfApplicationNodeSpec) DeepCopyInto(out *BpfApplicationNodeSpec) { + *out = *in + if in.Programs != nil { + in, out := &in.Programs, &out.Programs + *out = make(map[string]BpfApplicationProgramNode, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfApplicationNodeSpec. +func (in *BpfApplicationNodeSpec) DeepCopy() *BpfApplicationNodeSpec { + if in == nil { + return nil + } + out := new(BpfApplicationNodeSpec) + in.DeepCopyInto(out) + return out +} + // 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 @@ -183,40 +311,59 @@ func (in *BpfApplicationProgram) DeepCopy() *BpfApplicationProgram { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BpfApplicationSpec) DeepCopyInto(out *BpfApplicationSpec) { +func (in *BpfApplicationProgramNode) DeepCopyInto(out *BpfApplicationProgramNode) { *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]) - } + 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(XdpProgramInfoNode) + (*in).DeepCopyInto(*out) + } + if in.TC != nil { + in, out := &in.TC, &out.TC + *out = new(TcProgramInfoNode) + (*in).DeepCopyInto(*out) + } + if in.Fentry != nil { + in, out := &in.Fentry, &out.Fentry + *out = new(FentryProgramInfoNode) + (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfApplicationSpec. -func (in *BpfApplicationSpec) DeepCopy() *BpfApplicationSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BpfApplicationProgramNode. +func (in *BpfApplicationProgramNode) DeepCopy() *BpfApplicationProgramNode { if in == nil { return nil } - out := new(BpfApplicationSpec) + out := new(BpfApplicationProgramNode) in.DeepCopyInto(out) return out } // 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 *BpfApplicationSpec) DeepCopyInto(out *BpfApplicationSpec) { *out = *in - in.BpfProgramStatusCommon.DeepCopyInto(&out.BpfProgramStatusCommon) + 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() + } + } } -// 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 BpfApplicationSpec. +func (in *BpfApplicationSpec) DeepCopy() *BpfApplicationSpec { if in == nil { return nil } - out := new(BpfApplicationStatus) + out := new(BpfApplicationSpec) 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,42 @@ 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 *FentryAttachInfoNode) DeepCopyInto(out *FentryAttachInfoNode) { + *out = *in + in.AttachInfoCommon.DeepCopyInto(&out.AttachInfoCommon) + 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 FentryAttachInfoNode. +func (in *FentryAttachInfoNode) DeepCopy() *FentryAttachInfoNode { + if in == nil { + return nil + } + out := new(FentryAttachInfoNode) + 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 +823,7 @@ func (in *FentryProgram) DeepCopyObject() runtime.Object { func (in *FentryProgramInfo) DeepCopyInto(out *FentryProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) + out.FentryLoadInfo = in.FentryLoadInfo } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FentryProgramInfo. @@ -674,6 +836,22 @@ 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 *FentryProgramInfoNode) DeepCopyInto(out *FentryProgramInfoNode) { + *out = *in + in.AttachPoint.DeepCopyInto(&out.AttachPoint) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FentryProgramInfoNode. +func (in *FentryProgramInfoNode) DeepCopy() *FentryProgramInfoNode { + if in == nil { + return nil + } + out := new(FentryProgramInfoNode) + 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 +902,16 @@ 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 *FexitLoadInfo) DeepCopyInto(out *FexitLoadInfo) { *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 FexitLoadInfo. +func (in *FexitLoadInfo) DeepCopy() *FexitLoadInfo { if in == nil { return nil } - out := new(FentryProgramStatus) + out := new(FexitLoadInfo) in.DeepCopyInto(out) return out } @@ -770,6 +947,7 @@ func (in *FexitProgram) DeepCopyObject() runtime.Object { func (in *FexitProgramInfo) DeepCopyInto(out *FexitProgramInfo) { *out = *in in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) + out.FexitLoadInfo = in.FexitLoadInfo } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FexitProgramInfo. @@ -831,22 +1009,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 +1053,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 +1099,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 +1166,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 *TcAttachInfoNode) DeepCopyInto(out *TcAttachInfoNode) { + *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 TcAttachInfoNode. +func (in *TcAttachInfoNode) DeepCopy() *TcAttachInfoNode { + if in == nil { + return nil + } + out := new(TcAttachInfoNode) + 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 +1275,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 +1374,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 +1393,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 *TcProgramInfoNode) DeepCopyInto(out *TcProgramInfoNode) { + *out = *in + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]TcAttachInfoNode, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcProgramInfoNode. +func (in *TcProgramInfoNode) DeepCopy() *TcProgramInfoNode { + if in == nil { + return nil + } + out := new(TcProgramInfoNode) + 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 +1465,39 @@ 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.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) + } } -// 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 TcxAttachInfo. +func (in *TcxAttachInfo) DeepCopy() *TcxAttachInfo { if in == nil { return nil } - out := new(TcProgramStatus) + 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 *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 +1533,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 +1632,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]) + } } } @@ -1410,17 +1701,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 +1746,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 +1813,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 - in.BpfProgramStatusCommon.DeepCopyInto(&out.BpfProgramStatusCommon) + 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 } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TracepointProgramStatus. -func (in *TracepointProgramStatus) DeepCopy() *TracepointProgramStatus { +// 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.Containers.DeepCopyInto(&out.Containers) +} + +// 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 +1879,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 +1978,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 +2047,75 @@ func (in *UprobeProgramSpec) DeepCopy() *UprobeProgramSpec { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UprobeProgramStatus) DeepCopyInto(out *UprobeProgramStatus) { +func (in *XdpAttachInfo) DeepCopyInto(out *XdpAttachInfo) { *out = *in - in.BpfProgramStatusCommon.DeepCopyInto(&out.BpfProgramStatusCommon) + in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) + if in.Containers != nil { + in, out := &in.Containers, &out.Containers + *out = new(ContainerSelector) + (*in).DeepCopyInto(*out) + } + if in.ProceedOn != nil { + in, out := &in.ProceedOn, &out.ProceedOn + *out = make([]XdpProceedOnValue, len(*in)) + copy(*out, *in) + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UprobeProgramStatus. -func (in *UprobeProgramStatus) DeepCopy() *UprobeProgramStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new XdpAttachInfo. +func (in *XdpAttachInfo) DeepCopy() *XdpAttachInfo { if in == nil { return nil } - out := new(UprobeProgramStatus) + out := new(XdpAttachInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *XdpAttachInfoNode) DeepCopyInto(out *XdpAttachInfoNode) { + *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 XdpAttachInfoNode. +func (in *XdpAttachInfoNode) DeepCopy() *XdpAttachInfoNode { + if in == nil { + return nil + } + out := new(XdpAttachInfoNode) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *XdpNsAttachInfo) DeepCopyInto(out *XdpNsAttachInfo) { + *out = *in + in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) + in.Containers.DeepCopyInto(&out.Containers) + if in.ProceedOn != nil { + in, out := &in.ProceedOn, &out.ProceedOn + *out = make([]XdpProceedOnValue, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new XdpNsAttachInfo. +func (in *XdpNsAttachInfo) DeepCopy() *XdpNsAttachInfo { + if in == nil { + return nil + } + out := new(XdpNsAttachInfo) in.DeepCopyInto(out) return out } @@ -1775,12 +2151,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 +2250,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 +2269,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 *XdpProgramInfoNode) DeepCopyInto(out *XdpProgramInfoNode) { + *out = *in + if in.AttachPoints != nil { + in, out := &in.AttachPoints, &out.AttachPoints + *out = make([]XdpAttachInfoNode, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new XdpProgramInfoNode. +func (in *XdpProgramInfoNode) DeepCopy() *XdpProgramInfoNode { + if in == nil { + return nil + } + out := new(XdpProgramInfoNode) + 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 +2343,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..36f0c2322 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{}, + &BpfApplicationNode{}, + &BpfApplicationNodeList{}, &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..66ca7641e 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 @@ -4,6 +4,32 @@ metadata: creationTimestamp: null name: bpfman-agent-role rules: +- apiGroups: + - bpfman.io + resources: + - bpfapplicationnodes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - bpfman.io + resources: + - bpfapplicationnodes/finalizers + verbs: + - update +- apiGroups: + - bpfman.io + resources: + - bpfapplicationnodes/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 f5381cc75..ee3a74738 100644 --- a/bundle/manifests/bpfman-operator.clusterserviceversion.yaml +++ b/bundle/manifests/bpfman-operator.clusterserviceversion.yaml @@ -20,79 +20,22 @@ 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" - }, - { - "tcx": { - "bpffunctionname": "tcx_stats", - "direction": "ingress", - "interfaceselector": { - "primarynodeinterface": true - }, - "priority": 500 - }, - "type": "TCX" - }, - { - "type": "Uprobe", - "uprobe": { - "bpffunctionname": "uprobe_counter", - "containers": { - "containernames": [ - "bpfman", - "bpfman-agent" - ], - "namespace": "bpfman", - "pods": { - "matchLabels": { - "name": "bpfman-daemon" - } - } - }, - "func_name": "malloc", - "retprobe": false, - "target": "libc" - } - }, - { + "programs": { + "xdp_stats": { "type": "XDP", "xdp": { - "bpffunctionname": "xdp_stats", - "interfaceselector": { - "primarynodeinterface": true - }, - "priority": 55 + "attach_points": [ + { + "interfaceselector": { + "primarynodeinterface": true + }, + "priority": 55 + } + ], + "bpffunctionname": "xdp_stats" } } - ] + } } }, { @@ -619,7 +562,7 @@ metadata: capabilities: Basic Install categories: OpenShift Optional containerImage: quay.io/bpfman/bpfman-operator:latest - createdAt: "2025-01-03T19:50:49Z" + createdAt: "2025-01-22T13:10:53Z" features.operators.openshift.io/cnf: "false" features.operators.openshift.io/cni: "false" features.operators.openshift.io/csi: "true" @@ -664,6 +607,9 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: + - kind: BpfApplicationNode + name: bpfapplicationnodes.bpfman.io + version: v1alpha1 - description: BpfApplication is the Schema for the bpfapplications API displayName: Bpf Application kind: BpfApplication @@ -1079,6 +1025,14 @@ spec: - patch - update - watch + - apiGroups: + - bpfman.io + resources: + - bpfapplicationnodes + verbs: + - get + - list + - watch - apiGroups: - bpfman.io resources: diff --git a/bundle/manifests/bpfman.io_bpfapplicationnodes.yaml b/bundle/manifests/bpfman.io_bpfapplicationnodes.yaml new file mode 100644 index 000000000..c88014417 --- /dev/null +++ b/bundle/manifests/bpfman.io_bpfapplicationnodes.yaml @@ -0,0 +1,428 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + creationTimestamp: null + name: bpfapplicationnodes.bpfman.io +spec: + group: bpfman.io + names: + kind: BpfApplicationNode + listKind: BpfApplicationNodeList + plural: bpfapplicationnodes + singular: bpfapplicationnode + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.labels['kubernetes.io/hostname'] + name: Node + type: string + - jsonPath: .status.conditions[0].reason + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: BpfApplicationNode is the Schema for the bpfapplications API + 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: |- + BpfApplicationProgramNode defines the desired state of BpfApplication + // +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 == '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. + FentryAttachInfoNode is similar to FentryAttachInfo, but the interface and + container selectors are expanded, and we have one instance of + FentryAttachInfoNode for each unique attach point. The list is optional and + may be udated after the bpf program has been loaded. + 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 + 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 + - should_attach + - uuid + type: object + 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 + 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. + TcAttachInfoNode is similar to TcAttachInfo, but the interface and + container selectors are expanded, and we have one instance of + TcAttachInfoNode for each unique attach point. The list is optional and + may be udated after the bpf program has been loaded. + items: + properties: + attachid: + description: |- + An identifier for the attach point assigned by bpfman. This field is + empty until the program is successfully attached and bpfman returns the + id. + ANF-TODO: For the POC, this will be the program ID. + format: int32 + type: integer + attachstatus: + description: AttachStatus reflects whether the attachment + has been reconciled successfully, and if not, why. + type: string + containerpid: + description: Optional container pid to attach the + tc program in. + format: int32 + type: integer + direction: + description: |- + Direction specifies the direction of traffic the tc program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + ifname: + description: Interface name to attach the tc program + to. + type: string + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + description: |- + ProceedOn allows the user to call other tc programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - unspec + - ok + - reclassify + - shot + - pipe + - stolen + - queued + - repeat + - redirect + - trap + - dispatcher_return + type: string + maxItems: 11 + type: array + should_attach: + description: ShouldAttach reflects whether the attachment + should exist. + type: boolean + uuid: + description: |- + ANF-TODO: Putting a uuid here for now to maintain compatibility with the + existing BpfProgram. + type: string + required: + - attachid + - attachstatus + - direction + - ifname + - priority + - proceedon + - should_attach + - uuid + type: object + type: array + type: object + 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. + XdpAttachInfoNode is similar to XdpAttachInfo, but the interface and + container selectors are expanded, and we have one instance of + XdpAttachInfoNode 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: tc configuration is required when type is TC, and forbidden + otherwise + rule: 'has(self.type) && self.type == ''TC'' ? has(self.tc) : + !has(self.tc)' + - 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 BpfApplicationProgramNode + elements. + type: object + updatecount: + description: |- + The number of times the BpfApplicationNode 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 BpfApplicationNode + object + properties: + conditions: + description: |- + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationNode 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_bpfapplications.yaml b/bundle/manifests/bpfman.io_bpfapplications.yaml index fde48711d..ce292c575 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,28 @@ spec: description: fentry defines the desired state of the application's FentryPrograms. properties: + attach: + default: false + description: |- + Whether the program should be attached to the function. + This may be updated after the program has been loaded. + 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. @@ -226,23 +283,34 @@ spec: x-kubernetes-map-type: atomic required: - bpffunctionname - - func_name + - function_name type: object fexit: description: fexit defines the desired state of the application's FexitPrograms. properties: + attach: + default: false + description: |- + Whether the program should be attached to the function. + This may be updated after the program has been loaded. + 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. @@ -292,23 +360,52 @@ spec: x-kubernetes-map-type: atomic required: - 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 +453,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 +547,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: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the 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 +752,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: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tcx program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the 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: + - 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 +934,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 +1015,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 +1036,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 +1201,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: + 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 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 +1373,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: |- + 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: |- - 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. @@ -1354,34 +1561,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 +1606,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 BpfApplicationNode + 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 BpfApplicationNode 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_bpfnsapplications.yaml b/bundle/manifests/bpfman.io_bpfnsapplications.yaml index 9a355155b..8a56efea2 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 BpfApplicationNode + 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 BpfApplicationNode 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..88535df2c 100644 --- a/bundle/manifests/bpfman.io_fentryprograms.yaml +++ b/bundle/manifests/bpfman.io_fentryprograms.yaml @@ -53,8 +53,18 @@ spec: spec: description: FentryProgramSpec defines the desired state of FentryProgram properties: + attach: + default: false + description: |- + Whether the program should be attached to the function. + This may be updated after the program has been loaded. + 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 +113,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 +226,71 @@ 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 - - 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 BpfApplicationNode + 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 BpfApplicationNode 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..0e0971e53 100644 --- a/bundle/manifests/bpfman.io_fexitprograms.yaml +++ b/bundle/manifests/bpfman.io_fexitprograms.yaml @@ -53,8 +53,18 @@ spec: spec: description: FexitProgramSpec defines the desired state of FexitProgram properties: + attach: + default: false + description: |- + Whether the program should be attached to the function. + This may be updated after the program has been loaded. + 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 +113,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 +226,71 @@ 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 - - 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 BpfApplicationNode + 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 BpfApplicationNode 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..6db7eb496 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 BpfApplicationNode + 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 BpfApplicationNode 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..c6cb0649d 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 BpfApplicationNode + 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 BpfApplicationNode 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..387a34b10 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 BpfApplicationNode + 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 BpfApplicationNode 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..1cfcbe8c5 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 BpfApplicationNode + 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 BpfApplicationNode 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..53422ec16 100644 --- a/bundle/manifests/bpfman.io_tcxprograms.yaml +++ b/bundle/manifests/bpfman.io_tcxprograms.yaml @@ -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 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: + - 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 BpfApplicationNode + 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 BpfApplicationNode 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..c3e45e48b 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 BpfApplicationNode + 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 BpfApplicationNode 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..49d6722c3 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 BpfApplicationNode + 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 BpfApplicationNode 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..175bf3b7f 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 BpfApplicationNode + 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 BpfApplicationNode 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..abe3adb04 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 BpfApplicationNode 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..be0ddac00 100644 --- a/bundle/manifests/bpfman.io_xdpprograms.yaml +++ b/bundle/manifests/bpfman.io_xdpprograms.yaml @@ -61,8 +61,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 +236,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 +246,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 +345,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 BpfApplicationNode + 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 BpfApplicationNode 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..d29148cce 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.BpfApplicationNode, bpfmaniov1alpha1.BpfApplicationNodeList]{ 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_bpfapplicationnodes.yaml b/config/crd/bases/bpfman.io_bpfapplicationnodes.yaml new file mode 100644 index 000000000..760d53930 --- /dev/null +++ b/config/crd/bases/bpfman.io_bpfapplicationnodes.yaml @@ -0,0 +1,422 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: bpfapplicationnodes.bpfman.io +spec: + group: bpfman.io + names: + kind: BpfApplicationNode + listKind: BpfApplicationNodeList + plural: bpfapplicationnodes + singular: bpfapplicationnode + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.labels['kubernetes.io/hostname'] + name: Node + type: string + - jsonPath: .status.conditions[0].reason + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: BpfApplicationNode is the Schema for the bpfapplications API + 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: |- + BpfApplicationProgramNode defines the desired state of BpfApplication + // +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 == '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. + FentryAttachInfoNode is similar to FentryAttachInfo, but the interface and + container selectors are expanded, and we have one instance of + FentryAttachInfoNode for each unique attach point. The list is optional and + may be udated after the bpf program has been loaded. + 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 + 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 + - should_attach + - uuid + type: object + 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 + 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. + TcAttachInfoNode is similar to TcAttachInfo, but the interface and + container selectors are expanded, and we have one instance of + TcAttachInfoNode for each unique attach point. The list is optional and + may be udated after the bpf program has been loaded. + items: + properties: + attachid: + description: |- + An identifier for the attach point assigned by bpfman. This field is + empty until the program is successfully attached and bpfman returns the + id. + ANF-TODO: For the POC, this will be the program ID. + format: int32 + type: integer + attachstatus: + description: AttachStatus reflects whether the attachment + has been reconciled successfully, and if not, why. + type: string + containerpid: + description: Optional container pid to attach the + tc program in. + format: int32 + type: integer + direction: + description: |- + Direction specifies the direction of traffic the tc program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + ifname: + description: Interface name to attach the tc program + to. + type: string + priority: + description: |- + Priority specifies the priority of the tc program in relation to + other programs of the same type with the same attach point. It is a value + from 0 to 1000 where lower values have higher precedence. + format: int32 + maximum: 1000 + minimum: 0 + type: integer + proceedon: + description: |- + ProceedOn allows the user to call other tc programs in chain on this exit code. + Multiple values are supported by repeating the parameter. + items: + enum: + - unspec + - ok + - reclassify + - shot + - pipe + - stolen + - queued + - repeat + - redirect + - trap + - dispatcher_return + type: string + maxItems: 11 + type: array + should_attach: + description: ShouldAttach reflects whether the attachment + should exist. + type: boolean + uuid: + description: |- + ANF-TODO: Putting a uuid here for now to maintain compatibility with the + existing BpfProgram. + type: string + required: + - attachid + - attachstatus + - direction + - ifname + - priority + - proceedon + - should_attach + - uuid + type: object + type: array + type: object + 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. + XdpAttachInfoNode is similar to XdpAttachInfo, but the interface and + container selectors are expanded, and we have one instance of + XdpAttachInfoNode 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: tc configuration is required when type is TC, and forbidden + otherwise + rule: 'has(self.type) && self.type == ''TC'' ? has(self.tc) : + !has(self.tc)' + - 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 BpfApplicationProgramNode + elements. + type: object + updatecount: + description: |- + The number of times the BpfApplicationNode 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 BpfApplicationNode + object + properties: + conditions: + description: |- + For a BpfApplication object, Conditions contains the global cluster state + for the object. For a BpfApplicationNode 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_bpfapplications.yaml b/config/crd/bases/bpfman.io_bpfapplications.yaml index da9ec0e06..06399f133 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,28 @@ spec: description: fentry defines the desired state of the application's FentryPrograms. properties: + attach: + default: false + description: |- + Whether the program should be attached to the function. + This may be updated after the program has been loaded. + 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. @@ -226,23 +283,34 @@ spec: x-kubernetes-map-type: atomic required: - bpffunctionname - - func_name + - function_name type: object fexit: description: fexit defines the desired state of the application's FexitPrograms. properties: + attach: + default: false + description: |- + Whether the program should be attached to the function. + This may be updated after the program has been loaded. + 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. @@ -292,23 +360,52 @@ spec: x-kubernetes-map-type: atomic required: - 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 +453,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 +547,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: - description: |- - BpfFunctionName is the name of the function that is the entry point for the BPF - program - type: string - containers: + attach_points: description: |- - Containers identifies the set of containers in which to attach the eBPF - program. If Containers is not specified, the BPF program will be attached - in the root network namespace. - properties: - containernames: - description: |- - Name(s) of container(s). If none are specified, all containers in the - pod are selected. - items: - type: string - type: array - namespace: - default: "" - description: Target namespaces. - type: string - pods: - description: |- - Target pods. This field must be specified, to select all pods use - standard metav1.LabelSelector semantics and make it empty. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: + The list of points to which the program should be attached. The list is + optional and may be udated after the bpf program has been loaded + items: + properties: + containers: + description: |- + Containers identifies the set of containers in which to attach the eBPF + program. If Containers is not specified, the BPF program will be attached + in the root network namespace. + properties: + containernames: + description: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the 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 +752,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: |- + Name(s) of container(s). If none are specified, all containers in the + pod are selected. + items: + type: string + type: array + namespace: + default: "" + description: Target namespaces. + type: string + pods: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + Target pods. This field must be specified, to select all pods use + standard metav1.LabelSelector semantics and make it empty. properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. items: - type: string + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object type: array x-kubernetes-list-type: atomic - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: - type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object - type: object - x-kubernetes-map-type: atomic - required: - - pods - type: object - direction: + x-kubernetes-map-type: atomic + required: + - pods + type: object + direction: + description: |- + Direction specifies the direction of traffic the tcx program should + attach to for a given network device. + enum: + - ingress + - egress + type: string + interfaceselector: + description: Selector to determine the network interface + (or interfaces) + maxProperties: 1 + minProperties: 1 + properties: + interfaces: + description: |- + Interfaces refers to a list of network interfaces to attach the BPF + program to. + items: + type: string + type: array + primarynodeinterface: + description: Attach BPF program to the primary + interface on the node. Only 'true' accepted. + type: boolean + type: object + priority: + description: |- + Priority specifies the priority of the 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: + - 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 +934,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 +1015,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 +1036,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 +1201,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: + 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 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 +1373,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: |- + 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: |- - 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. @@ -1354,34 +1561,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 +1606,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 BpfApplicationNode + 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 BpfApplicationNode 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_bpfnsapplications.yaml b/config/crd/bases/bpfman.io_bpfnsapplications.yaml index 403eaf2e2..9e2ba2699 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 BpfApplicationNode + 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 BpfApplicationNode 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..b5bcb5ceb 100644 --- a/config/crd/bases/bpfman.io_fentryprograms.yaml +++ b/config/crd/bases/bpfman.io_fentryprograms.yaml @@ -53,8 +53,18 @@ spec: spec: description: FentryProgramSpec defines the desired state of FentryProgram properties: + attach: + default: false + description: |- + Whether the program should be attached to the function. + This may be updated after the program has been loaded. + 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 +113,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 +226,71 @@ 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 - - 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 BpfApplicationNode + 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 BpfApplicationNode 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..46c1b582a 100644 --- a/config/crd/bases/bpfman.io_fexitprograms.yaml +++ b/config/crd/bases/bpfman.io_fexitprograms.yaml @@ -53,8 +53,18 @@ spec: spec: description: FexitProgramSpec defines the desired state of FexitProgram properties: + attach: + default: false + description: |- + Whether the program should be attached to the function. + This may be updated after the program has been loaded. + 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 +113,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 +226,71 @@ 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 - - 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 BpfApplicationNode + 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 BpfApplicationNode 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..df0747b27 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 BpfApplicationNode + 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 BpfApplicationNode 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..421f7ebed 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 BpfApplicationNode + 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 BpfApplicationNode 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..b35b3bc73 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 BpfApplicationNode + 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 BpfApplicationNode 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..9193fd0b3 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 BpfApplicationNode + 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 BpfApplicationNode 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..74e71bdbd 100644 --- a/config/crd/bases/bpfman.io_tcxprograms.yaml +++ b/config/crd/bases/bpfman.io_tcxprograms.yaml @@ -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 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: + - 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 BpfApplicationNode + 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 BpfApplicationNode 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..32c5c60a7 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 BpfApplicationNode + 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 BpfApplicationNode 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..353dcaf82 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 BpfApplicationNode + 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 BpfApplicationNode 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..34ca890e0 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 BpfApplicationNode + 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 BpfApplicationNode 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..615aea987 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 BpfApplicationNode 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..988b0c7db 100644 --- a/config/crd/bases/bpfman.io_xdpprograms.yaml +++ b/config/crd/bases/bpfman.io_xdpprograms.yaml @@ -61,8 +61,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 +236,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 +246,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 +345,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 BpfApplicationNode + 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 BpfApplicationNode 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..d9c439878 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_bpfapplicationnodes.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..988eb632f 100644 --- a/config/rbac/bpfman-agent/role.yaml +++ b/config/rbac/bpfman-agent/role.yaml @@ -4,6 +4,32 @@ kind: ClusterRole metadata: name: agent-role rules: +- apiGroups: + - bpfman.io + resources: + - bpfapplicationnodes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - bpfman.io + resources: + - bpfapplicationnodes/finalizers + verbs: + - update +- apiGroups: + - bpfman.io + resources: + - bpfapplicationnodes/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..40c19f93a 100644 --- a/config/rbac/bpfman-operator/role.yaml +++ b/config/rbac/bpfman-operator/role.yaml @@ -16,6 +16,14 @@ rules: - patch - update - watch +- apiGroups: + - bpfman.io + resources: + - bpfapplicationnodes + 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..b1c5bcbdb 100644 --- a/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml +++ b/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml @@ -11,48 +11,54 @@ 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 - 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 + # - 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 + # - type: TCX + # tcx: + # bpffunctionname: tcx_stats + # 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 diff --git a/controllers/app-agent/application-common.go b/controllers/app-agent/application-common.go new file mode 100644 index 000000000..3920361e0 --- /dev/null +++ b/controllers/app-agent/application-common.go @@ -0,0 +1,515 @@ +/* +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" + "k8s.io/apimachinery/pkg/api/meta" + 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=bpfapplicationnodes,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationnodes/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationnodes/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 + progId *uint32 + finalizer string + recType string + Containers ContainerGetter +} + +type bpfmanApplication interface { + + // // *Program Reconciler + // // + // // 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) +} + +type bpfmanProgram interface { +} + +// 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 *BpfApplicationReconciler) 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 + updateSimpleStatus(&rec.currentAppNode.Spec.AppLoadStatus, bpfmaniov1alpha1.BpfProgCondNotSelected) + } else if rec.isBeingDeleted() { + // The program should be unloaded if necessary + updateSimpleStatus(&rec.currentAppNode.Spec.AppLoadStatus, bpfmaniov1alpha1.BpfProgCondUnloaded) + } else { + // The program should be loaded, but for now, just set the condition + updateSimpleStatus(&rec.currentAppNode.Spec.AppLoadStatus, 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 *BpfApplicationReconciler, + 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 BpfAppNode condition", "Name", rec.currentAppNode.GetName(), "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 +} + +func (r *BpfApplicationReconciler) updateBpfAppStatus( + ctx context.Context, + condition metav1.Condition, +) error { + r.currentAppNode.Status.Conditions = nil + meta.SetStatusCondition(&r.currentAppNode.Status.Conditions, condition) + return r.Status().Update(ctx, r.currentAppNode) +} + +// 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 *XdpProgramReconciler, isBeingDelete bool) error { + + mapOwnerStatus, err := r.processMapOwnerParam(ctx, *program) + if err != nil { + return err + } + + err = program.updateAttachInfo(ctx, isBeingDelete) + if err != nil { + return err + } + + err = program.processAttachInfo(ctx, program.currentProgram.XDP.BpfFunctionName, 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 XdpProgramReconciler) (*MapOwnerParamStatus, error) { + mapOwnerStatus := &MapOwnerParamStatus{ + isSet: false, + isFound: false, + isLoaded: false, + mapOwnerId: nil, + } + + r.Logger.V(1).Info("processMapOwnerParam()", "ctx", ctx, "rec.progId", rec.progId, "MapOwnerStatus", mapOwnerStatus) + + // ANF-TODO: Need to update this to support BpfApplicationNode. + 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 +} + +func (r *BpfApplicationReconciler) isBeingDeleted() bool { + return !r.currentApp.GetDeletionTimestamp().IsZero() +} + +// 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 *XdpProgramReconciler, + attachInfo *bpfmaniov1alpha1.XdpAttachInfoNode, + loadedBpfPrograms map[string]*gobpfman.ListResponse_ListResult, + bpfFunctionName string, + mapOwnerStatus *MapOwnerParamStatus) (bool, error) { + + loadedBpfProgram, isAttached := loadedBpfPrograms[string(attachInfo.UUID)] + + r.Logger.V(1).Info("reconcileBpfAttachment()", "shouldAttached", attachInfo.ShouldAttach, "isAttached", isAttached) + + switch attachInfo.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(attachInfo.AttachId, &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", *attachInfo.AttachId, + "Kernel ID", loadedBpfProgram.KernelInfo.Id) + attachInfo.AttachId = &loadedBpfProgram.KernelInfo.Id + } + // Confirm it's in the correct state. + loadRequest, err := rec.getLoadRequest(bpfFunctionName, attachInfo, mapOwnerStatus.mapOwnerId) + if err != nil { + attachInfo.AttachStatus = bpfmaniov1alpha1.BpfProgCondBytecodeSelectorError + return false, err + } + isSame, reasons := bpfmanagentinternal.DoesProgExist(loadedBpfProgram, loadRequest) + if !isSame { + r.Logger.Info("BpfProgram is in wrong state, unloading and reloading", "reason", reasons, "Program ID", attachInfo.AttachId) + if err := bpfmanagentinternal.UnloadBpfmanProgram(ctx, r.BpfmanClient, *attachInfo.AttachId); err != nil { + attachInfo.AttachStatus = bpfmaniov1alpha1.BpfProgCondNotUnloaded + r.Logger.Error(err, "Failed to unload eBPF Program") + return false, err + } + + r.Logger.Info("Calling bpfman to load eBPF Program on Node", "Name", "Program ID", attachInfo.AttachId) + attachInfo.AttachId, err = bpfmanagentinternal.LoadBpfmanProgram(ctx, r.BpfmanClient, loadRequest) + if err != nil { + attachInfo.AttachStatus = bpfmaniov1alpha1.BpfProgCondNotLoaded + r.Logger.Error(err, "Failed to load eBPF Program") + return false, err + } + attachInfo.AttachStatus = bpfmaniov1alpha1.BpfProgCondAttached + } else { + // Program exists and bpfProgram K8s Object is up to date + r.Logger.V(1).Info("BpfProgram is in correct state. Nothing to do in bpfman") + attachInfo.AttachStatus = bpfmaniov1alpha1.BpfProgCondAttached + } + case false: + // The program should be attached, but it isn't. + rec.Logger.Info("Program is not attached, calling getLoadRequest()") + loadRequest, err := rec.getLoadRequest(bpfFunctionName, attachInfo, mapOwnerStatus.mapOwnerId) + if err != nil { + attachInfo.AttachStatus = bpfmaniov1alpha1.BpfProgCondBytecodeSelectorError + return false, err + } + r.Logger.Info("Calling bpfman to load eBPF Program on node") + attachInfo.AttachId, err = bpfmanagentinternal.LoadBpfmanProgram(ctx, r.BpfmanClient, loadRequest) + if err != nil { + attachInfo.AttachStatus = bpfmaniov1alpha1.BpfProgCondNotLoaded + r.Logger.Error(err, "Failed to load eBPF Program") + return false, err + } + attachInfo.AttachStatus = 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 unload eBPF Program on node", "Program ID", attachInfo.AttachId) + if err := bpfmanagentinternal.UnloadBpfmanProgram(ctx, r.BpfmanClient, *attachInfo.AttachId); err != nil { + attachInfo.AttachStatus = bpfmaniov1alpha1.BpfProgCondNotUnloaded + r.Logger.Error(err, "Failed to unload eBPF Program") + return false, err + } + attachInfo.AttachStatus = bpfmaniov1alpha1.BpfProgCondNotAttached + case false: + // The program shouldn't be attached and it isn't. + attachInfo.AttachStatus = bpfmaniov1alpha1.BpfProgCondNotAttached + } + } + // The BPF program was successfully reconciled. + + remove := !attachInfo.ShouldAttach && attachInfo.AttachStatus == 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/application-program.go b/controllers/app-agent/application-program.go new file mode 100644 index 000000000..fac31cf7a --- /dev/null +++ b/controllers/app-agent/application-program.go @@ -0,0 +1,469 @@ +/* +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 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" + 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=bpfapplicationnodes,verbs=get;list;watch +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationnodes,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationnodes/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=bpfman.io,resources=bpfapplicationnodes/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 + currentAppNode *bpfmaniov1alpha1.BpfApplicationNode + ourNode *v1.Node +} + +func (r *BpfApplicationReconciler) getRecType() string { + return internal.ApplicationString +} + +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.currentAppNode.Status +} + +// 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.BpfApplicationNode{}, + 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 BpfApplicationNode 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 bpfAppNodeNew is true, then we need to create a new + // BpfApplicationNode at the end of the reconcile instead of just + // updating the existing one. + bpfAppNode, bpfAppNodeNew, err := r.getBpfAppNode(ctx, true) + if err != nil { + r.Logger.Error(err, "failed to get BpfApplicationNode") + return ctrl.Result{}, err + } + + // Save a copy of the original BpfApplicationNode 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 + // BpfApplicationNodes because they don't exist yet and will need to be + // created anyway. + var bpfAppNodeOriginal *bpfmaniov1alpha1.BpfApplicationNode + if !bpfAppNodeNew { + bpfAppNodeOriginal = bpfAppNode.DeepCopy() + } + + r.Logger.Info("From getBpfAppNode", "new", bpfAppNodeNew) + + r.currentAppNode = bpfAppNode + + 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.updateBpfAppNode(ctx, bpfAppNodeOriginal, bpfAppNodeNew) + 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 BpfApplicationNode 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 { + progNode, ok := bpfAppNode.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("XdpProgramNode not found"), + "XdpProgramNode 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: + // case bpfmaniov1alpha1.ProgTypeFexit: + // case bpfmaniov1alpha1.ProgTypeKprobe, + // case bpfmaniov1alpha1.ProgTypeUprobe, + // case bpfmaniov1alpha1.ProgTypeTracepoint: + // case bpfmaniov1alpha1.ProgTypeTC: + // case bpfmaniov1alpha1.ProgTypeTCX: + + case bpfmaniov1alpha1.ProgTypeXDP: + rec := &XdpProgramReconciler{ + ReconcilerCommon: r.ReconcilerCommon, + appCommon: r.currentApp.Spec.BpfAppCommon, + currentProgram: &prog, + currentProgramNode: &progNode, + ourNode: r.ourNode, + } + + 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 { + progNode.ProgramAttachStatus = bpfmaniov1alpha1.BpfProgCondAttachError + bpfApplicationStatus = bpfmaniov1alpha1.ProgramReconcileError + r.Logger.Error(err, "reconcile failure", "App Name", r.currentApp.Name, "Program Name", progName, "Type", prog.Type) + } else { + progNode.ProgramAttachStatus = bpfmaniov1alpha1.BpfProgCondAttached + r.Logger.Info("reconcile success", "App Name", r.currentApp.Name, "Program Name", progName, "Type", prog.Type) + } + + bpfAppNode.Spec.Programs[progName] = progNode + + r.Logger.Info("Done reconciling programs. Check for changes", "Application", i, "Name", r.currentAppNode.GetName()) + } + + // We've completed reconciling this program and if something has + // changed, we need to create or update the BpfApplicationNode. + objectChanged, err := r.updateBpfAppNode(ctx, bpfAppNodeOriginal, bpfAppNodeNew) + if err != nil { + r.Logger.Error(err, "failed to update BpfApplicationNode", "Name", r.currentAppNode.Name) + r.updateStatus(ctx, r, bpfmaniov1alpha1.ProgramReconcileError) + // If there was an error updating the object, requeue because we + // can't be sure what was updated and whether the manager will + // requeue us. + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationAgent}, nil + } + if objectChanged { + r.Logger.Info("BpfApplicationNode Spec changed", "Name", r.currentAppNode.Name) + return ctrl.Result{}, nil + } + + statusChanged := r.updateStatus(ctx, r, bpfApplicationStatus) + if statusChanged { + r.Logger.Info("BpfApplicationNode Status changed", "Name", r.currentAppNode.Name) + return ctrl.Result{}, nil + } + + if r.isBeingDeleted() { + r.Logger.Info("BpfApplication is being deleted", "Name", r.currentApp.Name) + if r.removeFinalizer(ctx, r.currentAppNode, r.finalizer) { + return ctrl.Result{}, nil + } + } + + // Nothing changed, so continue with next BpfApplication object. + r.Logger.Info("No changes to BpfApplicationNode object", "Name", r.currentAppNode.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 +} + +// updateBpfAppNode creates or updates the BpfApplicationNode 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) updateBpfAppNode(ctx context.Context, originalAppNode *bpfmaniov1alpha1.BpfApplicationNode, + bpfAppNodeNew bool) (bool, error) { + + // We've completed reconciling this program and something has + // changed. We need to create or update the BpfApplicationNode. + if bpfAppNodeNew { + // Create the BpfApplicationNode + r.currentAppNode.Spec.UpdateCount = 1 + r.Logger.Info("Creating new BpfApplicationNode object", "Name", r.currentAppNode.Name, + "bpfAppNodeNew", bpfAppNodeNew, "UpdateCount", r.currentAppNode.Spec.UpdateCount) + if err := r.Create(ctx, r.currentAppNode); err != nil { + r.Logger.Error(err, "failed to create BpfApplicationNode") + return true, err + } + r.waitForBpfAppNode(ctx) + // Creating a new BpfApplicationNode object will trigger another reconcile, so return. + return true, nil + } else if !reflect.DeepEqual(originalAppNode.Spec, r.currentAppNode.Spec) { + // Update the BpfApplicationNode + // + // ANF-TODO: Look into differentiating between a full update and + // just updating the status here via r.Status().Update(). It's + // possible for other fields to change while the status remains the + // same, but I'm not sure there is a case when we just update the + // status field. + // + // Updating a BpfApplicationNode object will trigger another reconcile, so return. + r.currentAppNode.Spec.UpdateCount = r.currentAppNode.Spec.UpdateCount + 1 + r.Logger.Info("Updating BpfApplicationNode object", "Name", r.currentAppNode.Name, "bpfAppNodeNew", bpfAppNodeNew, "UpdateCount", r.currentAppNode.Spec.UpdateCount) + if err := r.Update(ctx, r.currentAppNode); err != nil { + r.Logger.Error(err, "failed to update BpfApplicationNode") + return true, err + } + r.waitForBpfAppNode(ctx) + return true, nil + } + // Nothing changed and we didn't do an update. + return false, nil +} + +// bpfman saves state in the BpfApplicationNode 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. waitForBpfAppNode waits +// for the BpfApplicationNode object to be ready. +func (r *BpfApplicationReconciler) waitForBpfAppNode(ctx context.Context) error { + const maxRetries = 100 + const retryInterval = 100 * time.Millisecond + + var bpfAppNode *bpfmaniov1alpha1.BpfApplicationNode + var err error + r.Logger.Info("waitForBpfAppNode()", "UpdateCount", r.currentAppNode.Spec.UpdateCount, "currentGeneration", r.currentAppNode.GetGeneration()) + + for i := 0; i < maxRetries; i++ { + bpfAppNode, _, err = r.getBpfAppNode(ctx, false) + if err != nil { + return fmt.Errorf("error getting BpfApplicationNode: %v", err) + } + if bpfAppNode != nil && bpfAppNode.Spec.UpdateCount >= r.currentAppNode.Spec.UpdateCount { + r.Logger.Info("Found new bpfAppNode", "Attempt", i, "UpdateCount", bpfAppNode.Spec.UpdateCount, "currentGeneration", bpfAppNode.GetGeneration()) + return nil + } + time.Sleep(retryInterval) + } + + r.Logger.Info("Didn't find new BpfApplicationNode", "Attempts", maxRetries) + return fmt.Errorf("failed to get BpfApplicationNode after %d retries", maxRetries) +} + +// getBpfAppNode returns the BpfApplicationNode object for the current node. If +// needed to be created, the returned bool will be true. Otherwise, it will be false. +func (r *BpfApplicationReconciler) getBpfAppNode(ctx context.Context, createIfNotFound bool) (*bpfmaniov1alpha1.BpfApplicationNode, bool, error) { + + appProgramList := &bpfmaniov1alpha1.BpfApplicationNodeList{} + + opts := []client.ListOption{ + client.MatchingLabels{ + internal.BpfAppNodeOwner: 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 BpfApplicationNode, 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 BpfApplicationNodes for this BpfApplication on this node. + if createIfNotFound { + return r.createBpfAppNode() + } else { + return nil, false, nil + } +} + +func (r *BpfApplicationReconciler) createBpfAppNode() (*bpfmaniov1alpha1.BpfApplicationNode, bool, error) { + bpfAppNode := &bpfmaniov1alpha1.BpfApplicationNode{ + ObjectMeta: metav1.ObjectMeta{ + Name: generateUniqueName(r.currentApp.Name), + Finalizers: []string{r.finalizer}, + Labels: map[string]string{ + internal.BpfAppNodeOwner: r.currentApp.GetName(), + internal.K8sHostLabel: r.NodeName, + }, + }, + Spec: bpfmaniov1alpha1.BpfApplicationNodeSpec{ + AppLoadStatus: bpfmaniov1alpha1.BpfProgCondNotLoaded, + UpdateCount: 0, + Programs: map[string]bpfmaniov1alpha1.BpfApplicationProgramNode{}, + }, + Status: bpfmaniov1alpha1.BpfAppStatus{Conditions: []metav1.Condition{}}, + } + + err := r.initializeNodeProgramList(bpfAppNode) + if err != nil { + return nil, false, fmt.Errorf("failed to initialize BpfApplicationNode program list: %v", err) + } + + // Make the corresponding BpfProgramConfig the owner + if err := ctrl.SetControllerReference(r.currentApp, bpfAppNode, r.Scheme); err != nil { + return nil, false, fmt.Errorf("failed to set bpfAppNode object owner reference: %v", err) + } + + return bpfAppNode, true, nil +} + +func (r *BpfApplicationReconciler) initializeNodeProgramList(bpfAppNode *bpfmaniov1alpha1.BpfApplicationNode) error { + if len(bpfAppNode.Spec.Programs) != 0 { + return fmt.Errorf("BpfApplicationNode programs list not empty") + } + + for progName, prog := range r.currentApp.Spec.Programs { + progNode := bpfmaniov1alpha1.BpfApplicationProgramNode{ + Type: prog.Type, + } + switch prog.Type { + case bpfmaniov1alpha1.ProgTypeFentry: + panic(fmt.Sprintf("%v not implemented yet", prog.Type)) + 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: + panic(fmt.Sprintf("%v not implemented yet", prog.Type)) + 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: + progNode.XDP = &bpfmaniov1alpha1.XdpProgramInfoNode{} + default: + panic(fmt.Sprintf("unexpected v1alpha1.EBPFProgType: %#v", prog.Type)) + } + + bpfAppNode.Spec.Programs[progName] = progNode + } + + 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..7a305222e --- /dev/null +++ b/controllers/app-agent/application-program_test.go @@ -0,0 +1,384 @@ +package appagent + +import ( + "context" + "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" + xdpPriority = 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")} + + 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}, + }, + } + + 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.BpfApplicationNodeList{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfApplicationNode{}) + + // Create a fake client to mock API calls. + cl := fake.NewClientBuilder().WithStatusSubresource(bpfApp).WithStatusSubresource(&bpfmaniov1alpha1.BpfApplicationNode{}).WithRuntimeObjects(objs...).Build() + + cli := agenttestutils.NewBpfmanClientFake() + + rc := ReconcilerCommon{ + Client: cl, + Scheme: s, + BpfmanClient: cli, + NodeName: fakeNode.Name, + } + + // 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, + ourNode: fakeNode, + } + + // 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 BpfApplicationProgramNode 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 + bpfAppNode, bpfAppNodeNew, err := r.getBpfAppNode(ctx, false) + require.NoError(t, err) + + // Make sure we got bpfAppNode from the api server and didn't create a new + // one. + require.Equal(t, false, bpfAppNodeNew) + + require.Equal(t, fakeNode.Name, bpfAppNode.Labels[internal.K8sHostLabel]) + + require.Equal(t, appProgramName, bpfAppNode.Labels[internal.BpfAppNodeOwner]) + + require.Equal(t, internal.BpfApplicationControllerFinalizer, bpfAppNode.Finalizers[0]) + + // ANF-TODO: Check more fields? + + ////////////////////////////////////////////////////////// + // Do another reconcile and make sure there are no changes + ////////////////////////////////////////////////////////// + + 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 + bpfAppNode2, bpfAppNodeNew, err := r.getBpfAppNode(ctx, false) + require.NoError(t, err) + + // Make sure we got bpfAppNode from the api server and didn't create a new + // one. + require.Equal(t, false, bpfAppNodeNew) + + // require.Equal(t, string(bpfmaniov1alpha1.BpfProgCondLoaded), fentryBpfProg.Status.Conditions[0].Type) + require.Equal(t, 1, len(bpfAppNode2.Status.Conditions)) + require.Equal(t, string(bpfmaniov1alpha1.ProgramReconcileSuccess), bpfAppNode2.Status.Conditions[0].Type) + + // ANF-TODO: This needs to be checked after the 3rd reconcile + // // Check that the bpfAppNode was not updated + // require.True(t, reflect.DeepEqual(bpfAppNode, bpfAppNode2)) + + currentProgram := programMap[xdpBpfFunctionName] + + xdpReconciler := &XdpProgramReconciler{ + ReconcilerCommon: rc, + appCommon: bpfmaniov1alpha1.BpfAppCommon{ + NodeSelector: metav1.LabelSelector{}, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + currentProgram: ¤tProgram, + currentProgramNode: &bpfmaniov1alpha1.BpfApplicationProgramNode{}, + ourNode: fakeNode, + } + + attachPoint := bpfAppNode.Spec.Programs[xdpBpfFunctionName].XDP.AttachPoints[0] + + loadRequest, err := xdpReconciler.getLoadRequest(xdpBpfFunctionName, &attachPoint, nil) + require.NoError(t, err) + + r.Logger.Info("LoadRequest", "loadRequest:", loadRequest) + // {"loadRequest:": "bytecode:{file:\"/tmp/hello.o\"} name:\"XdpTest\" + // program_type:6 attach:{xdp_attach_info:{priority:50 iface:\"eth0\" + // proceed_on:2 proceed_on:31 netns:\"/host/proc/0/ns/net\"}} + // metadata:{key:\"bpfman.io/ProgramName\" value:\"BpfApplication\"} + // metadata:{key:\"bpfman.io/uuid\" + // value:\"1b464e84-c7b3-4dbf-beab-6de3447673c2\"}"} + + // rfentry := &FentryProgramReconciler{ClusterProgramReconciler: rc, ourNode: fakeNode} + // err = r.getBpfProgram(ctx, rfentry, name, fentryAppProgramId, fentryAttachPoint, fentryBpfProg) + // require.NoError(t, err) + + // require.NotEmpty(t, fentryBpfProg) + // // Finalizer is written + // require.Equal(t, internal.BpfApplicationControllerFinalizer, fentryBpfProg.Finalizers[0]) + // // owningConfig Label was correctly set + // require.Equal(t, name, fentryBpfProg.Labels[internal.BpfProgramOwner]) + // // node Label was correctly set + // require.Equal(t, fakeNode.Name, fentryBpfProg.Labels[internal.K8sHostLabel]) + // // fentry function Annotation was correctly set + // require.Equal(t, fentryFunctionName, fentryBpfProg.Annotations[internal.FentryProgramFunction]) + // // Type is set + // require.Equal(t, r.getRecType(), fentryBpfProg.Spec.Type) + // // Require no requeue + // require.False(t, res.Requeue) + + // // Update UID of bpfProgram with Fake UID since the fake API server won't + // fentryBpfProg.UID = types.UID(fentryFakeUID) + // err = cl.Update(ctx, fentryBpfProg) + // require.NoError(t, err) + + // // Second reconcile should create the bpfman Load Request and update the + // // BpfProgram object's maps field and id annotation. + // res, err = r.Reconcile(ctx, req) + // if err != nil { + // t.Fatalf("reconcile: (%v)", err) + // } + + // // Require no requeue + // require.False(t, res.Requeue) + + // // do Fentry Program + // expectedLoadReq := &gobpfman.LoadRequest{ + // Bytecode: &gobpfman.BytecodeLocation{ + // Location: &gobpfman.BytecodeLocation_File{File: bytecodePath}, + // }, + // Name: bpfFentryFunctionName, + // ProgramType: *internal.Tracing.Uint32(), + // Metadata: map[string]string{internal.UuidMetadataKey: string(fentryBpfProg.UID), internal.ProgramNameKey: name}, + // MapOwnerId: nil, + // Attach: &gobpfman.AttachInfo{ + // Info: &gobpfman.AttachInfo_FentryAttachInfo{ + // FentryAttachInfo: &gobpfman.FentryAttachInfo{ + // FnName: fentryFunctionName, + // }, + // }, + // }, + // } + + // // Check that the bpfProgram's programs was correctly updated + // err = r.getBpfProgram(ctx, rfentry, name, fentryAppProgramId, fentryAttachPoint, fentryBpfProg) + // require.NoError(t, err) + + // // prog ID should already have been set + // id, err := GetID(fentryBpfProg) + // require.NoError(t, err) + + // // Check the bpfLoadRequest was correctly Built + // if !cmp.Equal(expectedLoadReq, cli.LoadRequests[int(*id)], protocmp.Transform()) { + // cmp.Diff(expectedLoadReq, cli.LoadRequests[int(*id)], protocmp.Transform()) + // t.Logf("Diff %v", cmp.Diff(expectedLoadReq, cli.LoadRequests[int(*id)], protocmp.Transform())) + // t.Fatal("Built bpfman LoadRequest does not match expected") + // } + + // // Third reconcile should set the status to loaded + // res, err = r.Reconcile(ctx, req) + // if err != nil { + // t.Fatalf("reconcile: (%v)", err) + // } + + // // Require no requeue + // require.False(t, res.Requeue) + + // // Check that the bpfProgram's status was correctly updated + // err = r.getBpfProgram(ctx, rfentry, name, fentryAppProgramId, fentryAttachPoint, fentryBpfProg) + // require.NoError(t, err) + + // require.Equal(t, string(bpfmaniov1alpha1.BpfProgCondLoaded), fentryBpfProg.Status.Conditions[0].Type) + + // // do kprobe program + // // First reconcile should create the bpf program object + // res, err = r.Reconcile(ctx, req) + // if err != nil { + // t.Fatalf("reconcile: (%v)", err) + // } + + // rkprobe := &KprobeProgramReconciler{ClusterProgramReconciler: rc, ourNode: fakeNode} + // err = r.getBpfProgram(ctx, rkprobe, name, kprobeAppProgramId, kprobeAttachPoint, kprobeBpfProg) + // require.NoError(t, err) + + // require.NotEmpty(t, kprobeBpfProg) + // // Finalizer is written + // require.Equal(t, internal.BpfApplicationControllerFinalizer, kprobeBpfProg.Finalizers[0]) + // // owningConfig Label was correctly set + // require.Equal(t, name, kprobeBpfProg.Labels[internal.BpfProgramOwner]) + // // node Label was correctly set + // require.Equal(t, fakeNode.Name, kprobeBpfProg.Labels[internal.K8sHostLabel]) + // // fentry function Annotation was correctly set + // require.Equal(t, kprobeFunctionName, kprobeBpfProg.Annotations[internal.KprobeProgramFunction]) + // // Type is set + // require.Equal(t, r.getRecType(), kprobeBpfProg.Spec.Type) + // // Require no requeue + // require.False(t, res.Requeue) + + // // Update UID of bpfProgram with Fake UID since the fake API server won't + // kprobeBpfProg.UID = types.UID(kprobeFakeUID) + // err = cl.Update(ctx, kprobeBpfProg) + // require.NoError(t, err) + + // // Second reconcile should create the bpfman Load Request and update the + // // BpfProgram object's maps field and id annotation. + // res, err = r.Reconcile(ctx, req) + // if err != nil { + // t.Fatalf("reconcile: (%v)", err) + // } + + // // Require no requeue + // require.False(t, res.Requeue) + + // expectedLoadReq = &gobpfman.LoadRequest{ + // Bytecode: &gobpfman.BytecodeLocation{ + // Location: &gobpfman.BytecodeLocation_File{File: bytecodePath}, + // }, + // Name: bpfKprobeFunctionName, + // ProgramType: *internal.Kprobe.Uint32(), + // Metadata: map[string]string{internal.UuidMetadataKey: string(kprobeBpfProg.UID), internal.ProgramNameKey: name}, + // MapOwnerId: nil, + // Attach: &gobpfman.AttachInfo{ + // Info: &gobpfman.AttachInfo_KprobeAttachInfo{ + // KprobeAttachInfo: &gobpfman.KprobeAttachInfo{ + // FnName: kprobeFunctionName, + // Offset: uint64(kprobeOffset), + // Retprobe: kprobeRetprobe, + // ContainerPid: &kprobecontainerpid, + // }, + // }, + // }, + // } + + // // Check that the bpfProgram's programs was correctly updated + // err = r.getBpfProgram(ctx, rkprobe, name, kprobeAppProgramId, kprobeAttachPoint, kprobeBpfProg) + // require.NoError(t, err) + + // // prog ID should already have been set + // id, err = GetID(kprobeBpfProg) + // require.NoError(t, err) + + // // Check the bpfLoadRequest was correctly Built + // if !cmp.Equal(expectedLoadReq, cli.LoadRequests[int(*id)], protocmp.Transform()) { + // cmp.Diff(expectedLoadReq, cli.LoadRequests[int(*id)], protocmp.Transform()) + // t.Logf("Diff %v", cmp.Diff(expectedLoadReq, cli.LoadRequests[int(*id)], protocmp.Transform())) + // t.Fatal("Built bpfman LoadRequest does not match expected") + // } + + // // Third reconcile should set the status to loaded + // res, err = r.Reconcile(ctx, req) + // if err != nil { + // t.Fatalf("reconcile: (%v)", err) + // } + + // // Require no requeue + // require.False(t, res.Requeue) + + // // Check that the bpfProgram's status was correctly updated + // err = r.getBpfProgram(ctx, rkprobe, name, kprobeAppProgramId, kprobeAttachPoint, kprobeBpfProg) + // require.NoError(t, err) + + // require.Equal(t, string(bpfmaniov1alpha1.BpfProgCondLoaded), kprobeBpfProg.Status.Conditions[0].Type) +} diff --git a/controllers/app-agent/containers.go b/controllers/app-agent/containers.go new file mode 100644 index 000000000..721827dc1 --- /dev/null +++ b/controllers/app-agent/containers.go @@ -0,0 +1,252 @@ +/* +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 appagent + +import ( + "context" + "fmt" + "os/exec" + "slices" + "strconv" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + + "github.com/buger/jsonparser" + "github.com/go-logr/logr" +) + +type ContainerInfo struct { + podName string + containerName string + pid int64 +} + +// Create an interface for getting the list of containers in which the program +// should be attached so we can mock it in unit tests. +type ContainerGetter interface { + // Get the list of containers on this node that match the containerSelector. + GetContainers(ctx context.Context, + selectorNamespace string, + selectorPods metav1.LabelSelector, + selectorContainerNames *[]string, + logger logr.Logger) (*[]ContainerInfo, error) +} + +type RealContainerGetter struct { + nodeName string + clientSet kubernetes.Interface +} + +func NewRealContainerGetter(nodeName string) (*RealContainerGetter, error) { + clientSet, err := getClientset() + if err != nil { + return nil, fmt.Errorf("failed to get clientset: %v", err) + } + + containerGetter := RealContainerGetter{ + nodeName: nodeName, + clientSet: clientSet, + } + + return &containerGetter, nil +} + +func (c *RealContainerGetter) GetContainers( + ctx context.Context, + selectorNamespace string, + selectorPods metav1.LabelSelector, + selectorContainerNames *[]string, + logger logr.Logger) (*[]ContainerInfo, error) { + + // Get the list of pods that match the selector. + podList, err := c.getPodsForNode(ctx, selectorNamespace, selectorPods) + if err != nil { + return nil, fmt.Errorf("failed to get pod list: %v", err) + } + + // Get the list of containers in the list of pods that match the selector. + containerList, err := getContainerInfo(podList, selectorContainerNames, logger) + if err != nil { + return nil, fmt.Errorf("failed to get container info: %v", err) + } + + logger.V(1).Info("from getContainerInfo", "containers", containerList) + + return containerList, nil +} + +// getPodsForNode returns a list of pods on the given node that match the given +// container selector. +func (c *RealContainerGetter) getPodsForNode( + ctx context.Context, + selectorNamespace string, + selectorPods metav1.LabelSelector, +) (*v1.PodList, error) { + + selectorString := metav1.FormatLabelSelector(&selectorPods) + + if selectorString == "" { + return nil, fmt.Errorf("error parsing selector: %v", selectorString) + } + + listOptions := metav1.ListOptions{ + FieldSelector: "spec.nodeName=" + c.nodeName, + } + + if selectorString != "" { + listOptions.LabelSelector = selectorString + } + + podList, err := c.clientSet.CoreV1().Pods(selectorNamespace).List(ctx, listOptions) + if err != nil { + return nil, fmt.Errorf("error getting pod list: %v", err) + } + + return podList, nil +} + +// getContainerInfo returns a list of containerInfo for the given pod list and container names. +func getContainerInfo(podList *v1.PodList, containerNames *[]string, logger logr.Logger) (*[]ContainerInfo, error) { + + crictl := "/usr/local/bin/crictl" + + containers := []ContainerInfo{} + + for i, pod := range podList.Items { + logger.V(1).Info("Pod", "index", i, "Name", pod.Name, "Namespace", pod.Namespace, "NodeName", pod.Spec.NodeName) + + // Find the unique Pod ID of the given pod. + cmd := exec.Command(crictl, "pods", "--name", pod.Name, "-o", "json") + podInfo, err := cmd.Output() + if err != nil { + logger.Info("Failed to get pod info", "error", err) + return nil, err + } + + // The crictl --name option works like a grep on the names of pods. + // Since we are using the unique name of the pod generated by k8s, we + // will most likely only get one pod. Though very unlikely, it is + // technically possible that this unique name is a substring of another + // pod name. If that happens, we would get multiple pods, so we handle + // that possibility with the following for loop. + var podId string + podFound := false + for podIndex := 0; ; podIndex++ { + indexString := "[" + strconv.Itoa(podIndex) + "]" + podId, err = jsonparser.GetString(podInfo, "items", indexString, "id") + if err != nil { + // We hit the end of the list of pods and didn't find it. This + // should only happen if the pod was deleted between the time we + // got the list of pods and the time we got the info about the + // pod. + break + } + podName, err := jsonparser.GetString(podInfo, "items", indexString, "metadata", "name") + if err != nil { + // We shouldn't get an error here if we didn't get an error + // above, but just in case... + logger.Error(err, "Error getting pod name") + break + } + + if podName == pod.Name { + podFound = true + break + } + } + + if !podFound { + return nil, fmt.Errorf("pod %s not found in crictl pod list", pod.Name) + } + + logger.V(1).Info("podFound", "podId", podId, "err", err) + + // Get info about the containers in the pod so we can get their unique IDs. + cmd = exec.Command(crictl, "ps", "--pod", podId, "-o", "json") + containerData, err := cmd.Output() + if err != nil { + logger.Info("Failed to get container info", "error", err) + return nil, err + } + + // For each container in the pod... + for containerIndex := 0; ; containerIndex++ { + + indexString := "[" + strconv.Itoa(containerIndex) + "]" + + // Make sure the container name is in the list of containers we want. + containerName, err := jsonparser.GetString(containerData, "containers", indexString, "metadata", "name") + if err != nil { + break + } + + if containerNames != nil && + len(*containerNames) > 0 && + !slices.Contains((*containerNames), containerName) { + continue + } + + // If it is in the list, get the container ID. + containerId, err := jsonparser.GetString(containerData, "containers", indexString, "id") + if err != nil { + break + } + + // Now use the container ID to get more info about the container so + // we can get the PID. + cmd = exec.Command(crictl, "inspect", "-o", "json", containerId) + containerData, err := cmd.Output() + if err != nil { + logger.Info("Failed to get container data", "error", err) + continue + } + containerPid, err := jsonparser.GetInt(containerData, "info", "pid") + if err != nil { + logger.Info("Failed to get container PID", "error", err) + continue + } + + container := ContainerInfo{ + podName: pod.Name, + containerName: containerName, + pid: containerPid, + } + + containers = append(containers, container) + } + + } + + return &containers, nil +} + +// // Check if the annotation is set to indicate that no containers on this node +// // matched the container selector. +// func noContainersOnNode[T BpfProg](bpfProgram *T, annotationIndex string) bool { +// if bpfProgram == nil { +// return false +// } + +// annotations := (*bpfProgram).GetAnnotations() +// noContainersOnNode, ok := annotations[annotationIndex] +// if ok && noContainersOnNode == "true" { +// return true +// } + +// return false +// } diff --git a/controllers/app-agent/internal/auth.go b/controllers/app-agent/internal/auth.go new file mode 100644 index 000000000..b90c829a1 --- /dev/null +++ b/controllers/app-agent/internal/auth.go @@ -0,0 +1,144 @@ +/* +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 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..b068a9d87 --- /dev/null +++ b/controllers/app-agent/internal/bpfman-core.go @@ -0,0 +1,206 @@ +/* +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 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..1d316c1de --- /dev/null +++ b/controllers/app-agent/internal/cmp.go @@ -0,0 +1,183 @@ +/* +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 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..8cbd7e48d --- /dev/null +++ b/controllers/app-agent/internal/iface.go @@ -0,0 +1,63 @@ +/* +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 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..051e7e1ca --- /dev/null +++ b/controllers/app-agent/internal/test-utils/fake_bpfman_client.go @@ -0,0 +1,120 @@ +/* +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 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/xdp-program.go b/controllers/app-agent/xdp-program.go new file mode 100644 index 000000000..c8d57b3cd --- /dev/null +++ b/controllers/app-agent/xdp-program.go @@ -0,0 +1,358 @@ +/* +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. +*/ + +//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 + // 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 + currentProgramNode *bpfmaniov1alpha1.BpfApplicationProgramNode + ourNode *v1.Node +} + +func (r *XdpProgramReconciler) getFinalizer() string { + return r.finalizer +} + +// func (r *XdpProgramReconciler) getOwner() metav1.Object { +// if r.appOwner == nil { +// return r.currentXdpProgram +// } else { +// return r.appOwner +// } +// } + +func (r *XdpProgramReconciler) getRecType() string { + return r.recType +} + +func (r *XdpProgramReconciler) getProgType() internal.ProgramType { + return internal.Xdp +} + +// func (r *XdpProgramReconciler) getName() string { +// return r.currentXdpProgram.Name +// } + +// func (r *XdpProgramReconciler) getNamespace() string { +// return r.currentXdpProgram.Namespace +// } + +func (r *XdpProgramReconciler) getNode() *v1.Node { + return r.ourNode +} + +// func (r *XdpProgramReconciler) getBpfProgramCommon() *bpfmaniov1alpha1.BpfProgramCommon { +// return &r.currentXdpProgram.Spec.BpfProgramCommon +// } + +func (r *XdpProgramReconciler) getBpfGlobalData() map[string][]byte { + return r.appCommon.GlobalData +} + +// func (r *XdpProgramReconciler) getAppProgramId() string { +// return appProgramId(r.currentXdpProgram.GetLabels()) +// } + +// func (r *XdpProgramReconciler) setCurrentProgram(program client.Object) error { +// var err error +// var ok bool + +// r.currentXdpProgram, ok = program.(*bpfmaniov1alpha1.XdpProgram) +// if !ok { +// return fmt.Errorf("failed to cast program to XdpProgram") +// } + +// 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) +// } + +// return nil +// } + +// 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(bpfFunctionName string, reqAttachInfo *bpfmaniov1alpha1.XdpAttachInfoNode, + mapOwnerId *uint32) (*gobpfman.LoadRequest, error) { + + r.Logger.Info("Getting load request", "bpfFunctionName", bpfFunctionName, "reqAttachInfo", reqAttachInfo, "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: reqAttachInfo.Priority, + Iface: reqAttachInfo.IfName, + ProceedOn: xdpProceedOnToInt(reqAttachInfo.ProceedOn), + } + + if reqAttachInfo.ContainerPid != nil { + netns := fmt.Sprintf("/host/proc/%d/ns/net", *reqAttachInfo.ContainerPid) + attachInfo.Netns = &netns + } + + loadRequest := gobpfman.LoadRequest{ + Bytecode: bytecode, + Name: bpfFunctionName, + ProgramType: uint32(internal.Xdp), + Attach: &gobpfman.AttachInfo{ + Info: &gobpfman.AttachInfo_XdpAttachInfo{ + XdpAttachInfo: attachInfo, + }, + }, + Metadata: map[string]string{internal.UuidMetadataKey: string(reqAttachInfo.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 *AttachInfoNode. +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.currentProgramNode.XDP.AttachPoints { + r.currentProgramNode.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.currentProgramNode.XDP.AttachPoints[*index].AttachInfoCommon.ShouldAttach = true + } else { + // Attach point doesn't exist, so add it. + r.currentProgramNode.XDP.AttachPoints = append(r.currentProgramNode.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(attachInfoNode bpfmaniov1alpha1.XdpAttachInfoNode) *int { + for i, a := range r.currentProgramNode.XDP.AttachPoints { + // attachInfoNode is the same as a if the the following fields are the + // same: IfName, ContainerPid, Priority, and ProceedOn. + if a.IfName == attachInfoNode.IfName && reflect.DeepEqual(a.ContainerPid, attachInfoNode.ContainerPid) && + a.Priority == attachInfoNode.Priority && reflect.DeepEqual(a.ProceedOn, attachInfoNode.ProceedOn) { + return &i + } + } + return nil +} + +// processAttachInfo processes the attach points in *AttachInfoNode. 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, bpfFunctionName string, + mapOwnerStatus *MapOwnerParamStatus) error { + r.Logger.Info("Processing attach info", "bpfFunctionName", 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.currentProgramNode.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.currentProgramNode.XDP.AttachPoints { + remove, err := r.reconcileBpfAttachment(ctx, r, &r.currentProgramNode.XDP.AttachPoints[i], + loadedBpfPrograms, bpfFunctionName, 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.currentProgramNode.XDP.AttachPoints = removeAttachPoints(r.currentProgramNode.XDP.AttachPoints, attachPointsToRemove) + } + + return lastReconcileAttachmentError +} + +// removeAttachPoints removes attach points from a slice of attach points based on the keys in the map. +func removeAttachPoints(attachPoints []bpfmaniov1alpha1.XdpAttachInfoNode, attachPointsToRemove map[int]bool) []bpfmaniov1alpha1.XdpAttachInfoNode { + var newAttachPoints []bpfmaniov1alpha1.XdpAttachInfoNode + 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.XdpAttachInfoNode, 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.XdpAttachInfoNode{} + + 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.XdpAttachInfoNode{ + 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.XdpAttachInfoNode{ + 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..beca67c82 --- /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() + bpfAppNodeName = 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 + expectedBpfAppNode := &bpfmaniov1alpha1.BpfApplicationNode{ + ObjectMeta: metav1.ObjectMeta{ + Name: bpfAppNodeName, + 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.BpfApplicationNodeSpec{ + AppLoadStatus: bpfmaniov1alpha1.BpfProgCondLoaded, + Programs: map[string]bpfmaniov1alpha1.BpfApplicationProgramNode{}, + }, + Status: bpfmaniov1alpha1.BpfAppStatus{ + Conditions: []metav1.Condition{bpfmaniov1alpha1.ProgramReconcileSuccess.Condition("")}, + }, + } + + // Objects to track in the fake client. + objs := []runtime.Object{fakeNode, app, expectedBpfAppNode} + + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, app) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfApplicationNode{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfApplicationNodeList{}) + + // Create a fake client to mock API calls. + cl := fake.NewClientBuilder().WithStatusSubresource(app).WithRuntimeObjects(objs...).Build() + + rc := ReconcilerCommon[bpfmaniov1alpha1.BpfApplicationNode, bpfmaniov1alpha1.BpfApplicationNodeList]{ + 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..f7f23d362 --- /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.BpfApplicationNode, bpfmaniov1alpha1.BpfApplicationNodeList] { + 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.BpfApplicationNode{}, + &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) { + bpfAppNode := &bpfmaniov1alpha1.BpfApplicationNode{} + if err := r.Get(ctx, req.NamespacedName, bpfAppNode); 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(bpfAppNode) + 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..8461f5e7c --- /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=bpfapplicationnodes,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 + bpfAppNodeObjs, 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 (*bpfAppNodeObjs).GetItems() { + bpfProgramNode := program.GetLabels()[internal.K8sHostLabel] + if node.Name == bpfProgramNode { + 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 _, bpfAppNode := range (*bpfAppNodeObjs).GetItems() { + + if rec.containsFinalizer(&bpfAppNode, rec.getFinalizer()) { + finalApplied = append(finalApplied, bpfAppNode.GetName()) + } + + status := bpfAppNode.GetStatus() + if bpfmanHelpers.IsBpfAppNodeConditionFailure(&status.Conditions) { + failedBpfPrograms = append(failedBpfPrograms, bpfAppNode.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..a923cc417 --- /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.BpfApplicationNode, bpfmaniov1alpha1.BpfApplicationNodeList] +} + +//lint:ignore U1000 Linter claims function unused, but generics confusing linter +func (r *ClusterProgramReconciler) getBpfList( + ctx context.Context, + progName string, + _progNamespace string, +) (*bpfmaniov1alpha1.BpfApplicationNodeList, error) { + + bpfProgramList := &bpfmaniov1alpha1.BpfApplicationNodeList{} + + // 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.BpfApplicationNode, + 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.BpfApplicationNode) + newObject := e.ObjectNew.(*bpfmaniov1alpha1.BpfApplicationNode) + 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..ec73addf9 --- /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.BpfApplicationNode, bpfmaniov1alpha1.BpfApplicationNodeList]{ + 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..1a0d69344 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}, + 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..a5f1e05aa 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}, + 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..281c65b01 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}, + 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..b1c46fb4c 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}, + 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/fentry-program_test.go b/controllers/bpfman-operator/fentry-program_test.go index 335894de0..dd9567b47 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}, + Attach: true, }, }, } diff --git a/controllers/bpfman-operator/fexit-program_test.go b/controllers/bpfman-operator/fexit-program_test.go index d2077ece4..9556d17e0 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}, + 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..b42369cef 100644 --- a/internal/constants.go +++ b/internal/constants.go @@ -77,6 +77,7 @@ const ( // object. In the case of a BpfApplication, it will be the name of the // BpfApplication object. BpfProgramOwner = "bpfman.io/ownedByProgram" + BpfAppNodeOwner = "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/bpfapplicationnode.go b/pkg/client/apis/v1alpha1/bpfapplicationnode.go new file mode 100644 index 000000000..945299521 --- /dev/null +++ b/pkg/client/apis/v1alpha1/bpfapplicationnode.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" +) + +// BpfApplicationNodeLister helps list BpfApplicationNodes. +// All objects returned here must be treated as read-only. +type BpfApplicationNodeLister interface { + // List lists all BpfApplicationNodes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.BpfApplicationNode, err error) + // Get retrieves the BpfApplicationNode from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.BpfApplicationNode, error) + BpfApplicationNodeListerExpansion +} + +// bpfApplicationNodeLister implements the BpfApplicationNodeLister interface. +type bpfApplicationNodeLister struct { + indexer cache.Indexer +} + +// NewBpfApplicationNodeLister returns a new BpfApplicationNodeLister. +func NewBpfApplicationNodeLister(indexer cache.Indexer) BpfApplicationNodeLister { + return &bpfApplicationNodeLister{indexer: indexer} +} + +// List lists all BpfApplicationNodes in the indexer. +func (s *bpfApplicationNodeLister) List(selector labels.Selector) (ret []*v1alpha1.BpfApplicationNode, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.BpfApplicationNode)) + }) + return ret, err +} + +// Get retrieves the BpfApplicationNode from the index for a given name. +func (s *bpfApplicationNodeLister) Get(name string) (*v1alpha1.BpfApplicationNode, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("bpfapplicationnode"), name) + } + return obj.(*v1alpha1.BpfApplicationNode), nil +} diff --git a/pkg/client/apis/v1alpha1/expansion_generated.go b/pkg/client/apis/v1alpha1/expansion_generated.go index 491e889c5..180cc3b92 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{} +// BpfApplicationNodeListerExpansion allows custom methods to be added to +// BpfApplicationNodeLister. +type BpfApplicationNodeListerExpansion 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..e5d073b64 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 + BpfApplicationNodesGetter BpfNsApplicationsGetter BpfNsProgramsGetter BpfProgramsGetter @@ -55,6 +56,10 @@ func (c *BpfmanV1alpha1Client) BpfApplications() BpfApplicationInterface { return newBpfApplications(c) } +func (c *BpfmanV1alpha1Client) BpfApplicationNodes() BpfApplicationNodeInterface { + return newBpfApplicationNodes(c) +} + func (c *BpfmanV1alpha1Client) BpfNsApplications(namespace string) BpfNsApplicationInterface { return newBpfNsApplications(c, namespace) } diff --git a/pkg/client/clientset/typed/apis/v1alpha1/bpfapplicationnode.go b/pkg/client/clientset/typed/apis/v1alpha1/bpfapplicationnode.go new file mode 100644 index 000000000..7917e9661 --- /dev/null +++ b/pkg/client/clientset/typed/apis/v1alpha1/bpfapplicationnode.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" +) + +// BpfApplicationNodesGetter has a method to return a BpfApplicationNodeInterface. +// A group's client should implement this interface. +type BpfApplicationNodesGetter interface { + BpfApplicationNodes() BpfApplicationNodeInterface +} + +// BpfApplicationNodeInterface has methods to work with BpfApplicationNode resources. +type BpfApplicationNodeInterface interface { + Create(ctx context.Context, bpfApplicationNode *v1alpha1.BpfApplicationNode, opts v1.CreateOptions) (*v1alpha1.BpfApplicationNode, error) + Update(ctx context.Context, bpfApplicationNode *v1alpha1.BpfApplicationNode, opts v1.UpdateOptions) (*v1alpha1.BpfApplicationNode, error) + UpdateStatus(ctx context.Context, bpfApplicationNode *v1alpha1.BpfApplicationNode, opts v1.UpdateOptions) (*v1alpha1.BpfApplicationNode, 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.BpfApplicationNode, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.BpfApplicationNodeList, 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.BpfApplicationNode, err error) + BpfApplicationNodeExpansion +} + +// bpfApplicationNodes implements BpfApplicationNodeInterface +type bpfApplicationNodes struct { + client rest.Interface +} + +// newBpfApplicationNodes returns a BpfApplicationNodes +func newBpfApplicationNodes(c *BpfmanV1alpha1Client) *bpfApplicationNodes { + return &bpfApplicationNodes{ + client: c.RESTClient(), + } +} + +// Get takes name of the bpfApplicationNode, and returns the corresponding bpfApplicationNode object, and an error if there is any. +func (c *bpfApplicationNodes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.BpfApplicationNode, err error) { + result = &v1alpha1.BpfApplicationNode{} + err = c.client.Get(). + Resource("bpfapplicationnodes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of BpfApplicationNodes that match those selectors. +func (c *bpfApplicationNodes) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.BpfApplicationNodeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.BpfApplicationNodeList{} + err = c.client.Get(). + Resource("bpfapplicationnodes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested bpfApplicationNodes. +func (c *bpfApplicationNodes) 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("bpfapplicationnodes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a bpfApplicationNode and creates it. Returns the server's representation of the bpfApplicationNode, and an error, if there is any. +func (c *bpfApplicationNodes) Create(ctx context.Context, bpfApplicationNode *v1alpha1.BpfApplicationNode, opts v1.CreateOptions) (result *v1alpha1.BpfApplicationNode, err error) { + result = &v1alpha1.BpfApplicationNode{} + err = c.client.Post(). + Resource("bpfapplicationnodes"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(bpfApplicationNode). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a bpfApplicationNode and updates it. Returns the server's representation of the bpfApplicationNode, and an error, if there is any. +func (c *bpfApplicationNodes) Update(ctx context.Context, bpfApplicationNode *v1alpha1.BpfApplicationNode, opts v1.UpdateOptions) (result *v1alpha1.BpfApplicationNode, err error) { + result = &v1alpha1.BpfApplicationNode{} + err = c.client.Put(). + Resource("bpfapplicationnodes"). + Name(bpfApplicationNode.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(bpfApplicationNode). + 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 *bpfApplicationNodes) UpdateStatus(ctx context.Context, bpfApplicationNode *v1alpha1.BpfApplicationNode, opts v1.UpdateOptions) (result *v1alpha1.BpfApplicationNode, err error) { + result = &v1alpha1.BpfApplicationNode{} + err = c.client.Put(). + Resource("bpfapplicationnodes"). + Name(bpfApplicationNode.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(bpfApplicationNode). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the bpfApplicationNode and deletes it. Returns an error if one occurs. +func (c *bpfApplicationNodes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("bpfapplicationnodes"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *bpfApplicationNodes) 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("bpfapplicationnodes"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched bpfApplicationNode. +func (c *bpfApplicationNodes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.BpfApplicationNode, err error) { + result = &v1alpha1.BpfApplicationNode{} + err = c.client.Patch(pt). + Resource("bpfapplicationnodes"). + 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..1c91439c3 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) BpfApplicationNodes() v1alpha1.BpfApplicationNodeInterface { + return &FakeBpfApplicationNodes{c} +} + func (c *FakeBpfmanV1alpha1) BpfNsApplications(namespace string) v1alpha1.BpfNsApplicationInterface { return &FakeBpfNsApplications{c, namespace} } diff --git a/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_bpfapplicationnode.go b/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_bpfapplicationnode.go new file mode 100644 index 000000000..5690cf258 --- /dev/null +++ b/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_bpfapplicationnode.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" +) + +// FakeBpfApplicationNodes implements BpfApplicationNodeInterface +type FakeBpfApplicationNodes struct { + Fake *FakeBpfmanV1alpha1 +} + +var bpfapplicationnodesResource = v1alpha1.SchemeGroupVersion.WithResource("bpfapplicationnodes") + +var bpfapplicationnodesKind = v1alpha1.SchemeGroupVersion.WithKind("BpfApplicationNode") + +// Get takes name of the bpfApplicationNode, and returns the corresponding bpfApplicationNode object, and an error if there is any. +func (c *FakeBpfApplicationNodes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.BpfApplicationNode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(bpfapplicationnodesResource, name), &v1alpha1.BpfApplicationNode{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BpfApplicationNode), err +} + +// List takes label and field selectors, and returns the list of BpfApplicationNodes that match those selectors. +func (c *FakeBpfApplicationNodes) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.BpfApplicationNodeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(bpfapplicationnodesResource, bpfapplicationnodesKind, opts), &v1alpha1.BpfApplicationNodeList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.BpfApplicationNodeList{ListMeta: obj.(*v1alpha1.BpfApplicationNodeList).ListMeta} + for _, item := range obj.(*v1alpha1.BpfApplicationNodeList).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 bpfApplicationNodes. +func (c *FakeBpfApplicationNodes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(bpfapplicationnodesResource, opts)) +} + +// Create takes the representation of a bpfApplicationNode and creates it. Returns the server's representation of the bpfApplicationNode, and an error, if there is any. +func (c *FakeBpfApplicationNodes) Create(ctx context.Context, bpfApplicationNode *v1alpha1.BpfApplicationNode, opts v1.CreateOptions) (result *v1alpha1.BpfApplicationNode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(bpfapplicationnodesResource, bpfApplicationNode), &v1alpha1.BpfApplicationNode{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BpfApplicationNode), err +} + +// Update takes the representation of a bpfApplicationNode and updates it. Returns the server's representation of the bpfApplicationNode, and an error, if there is any. +func (c *FakeBpfApplicationNodes) Update(ctx context.Context, bpfApplicationNode *v1alpha1.BpfApplicationNode, opts v1.UpdateOptions) (result *v1alpha1.BpfApplicationNode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(bpfapplicationnodesResource, bpfApplicationNode), &v1alpha1.BpfApplicationNode{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BpfApplicationNode), 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 *FakeBpfApplicationNodes) UpdateStatus(ctx context.Context, bpfApplicationNode *v1alpha1.BpfApplicationNode, opts v1.UpdateOptions) (*v1alpha1.BpfApplicationNode, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(bpfapplicationnodesResource, "status", bpfApplicationNode), &v1alpha1.BpfApplicationNode{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BpfApplicationNode), err +} + +// Delete takes name of the bpfApplicationNode and deletes it. Returns an error if one occurs. +func (c *FakeBpfApplicationNodes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(bpfapplicationnodesResource, name, opts), &v1alpha1.BpfApplicationNode{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeBpfApplicationNodes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(bpfapplicationnodesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.BpfApplicationNodeList{}) + return err +} + +// Patch applies the patch and returns the patched bpfApplicationNode. +func (c *FakeBpfApplicationNodes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.BpfApplicationNode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(bpfapplicationnodesResource, name, pt, data, subresources...), &v1alpha1.BpfApplicationNode{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BpfApplicationNode), 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..11de54a6b 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 BpfApplicationNodeExpansion interface{} + type BpfNsApplicationExpansion interface{} type BpfNsProgramExpansion interface{} diff --git a/pkg/client/externalversions/apis/v1alpha1/bpfapplicationnode.go b/pkg/client/externalversions/apis/v1alpha1/bpfapplicationnode.go new file mode 100644 index 000000000..7a6c7212e --- /dev/null +++ b/pkg/client/externalversions/apis/v1alpha1/bpfapplicationnode.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" +) + +// BpfApplicationNodeInformer provides access to a shared informer and lister for +// BpfApplicationNodes. +type BpfApplicationNodeInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.BpfApplicationNodeLister +} + +type bpfApplicationNodeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewBpfApplicationNodeInformer constructs a new informer for BpfApplicationNode 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 NewBpfApplicationNodeInformer(client clientset.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredBpfApplicationNodeInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredBpfApplicationNodeInformer constructs a new informer for BpfApplicationNode 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 NewFilteredBpfApplicationNodeInformer(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().BpfApplicationNodes().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.BpfmanV1alpha1().BpfApplicationNodes().Watch(context.TODO(), options) + }, + }, + &apisv1alpha1.BpfApplicationNode{}, + resyncPeriod, + indexers, + ) +} + +func (f *bpfApplicationNodeInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredBpfApplicationNodeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *bpfApplicationNodeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisv1alpha1.BpfApplicationNode{}, f.defaultInformer) +} + +func (f *bpfApplicationNodeInformer) Lister() v1alpha1.BpfApplicationNodeLister { + return v1alpha1.NewBpfApplicationNodeLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/externalversions/apis/v1alpha1/interface.go b/pkg/client/externalversions/apis/v1alpha1/interface.go index 7ca2dcbec..f138e26eb 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 + // BpfApplicationNodes returns a BpfApplicationNodeInformer. + BpfApplicationNodes() BpfApplicationNodeInformer // 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} } +// BpfApplicationNodes returns a BpfApplicationNodeInformer. +func (v *version) BpfApplicationNodes() BpfApplicationNodeInformer { + return &bpfApplicationNodeInformer{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..3b6020da3 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("bpfapplicationnodes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Bpfman().V1alpha1().BpfApplicationNodes().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..6b4d503b6 100644 --- a/pkg/helpers/helpers.go +++ b/pkg/helpers/helpers.go @@ -326,3 +326,23 @@ func IsBpfProgramConditionFailure(conditions *[]metav1.Condition) bool { return false } + +func IsBpfAppNodeConditionFailure(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 + } +}