From d28de93ea212412719025c6363b0ba1870215b5e Mon Sep 17 00:00:00 2001 From: Mohamed Mahmoud Date: Tue, 13 Aug 2024 08:22:35 -0400 Subject: [PATCH 1/8] WIP: initial APIS for TCX ebpf program types Signed-off-by: Mohamed Mahmoud --- PROJECT | 7 + apis/v1alpha1/bpfapplication_types.go | 4 +- apis/v1alpha1/tcxProgram_types.go | 109 ++++++ apis/v1alpha1/zz_generated.deepcopy.go | 111 +++++- apis/v1alpha1/zz_generated.register.go | 2 + ...bpfman-operator.clusterserviceversion.yaml | 3 + .../manifests/bpfman.io_bpfapplications.yaml | 55 +-- bundle/manifests/bpfman.io_tcxprograms.yaml | 366 ++++++++++++++++++ .../crd/bases/bpfman.io_bpfapplications.yaml | 55 +-- config/crd/bases/bpfman.io_tcxprograms.yaml | 360 +++++++++++++++++ config/crd/kustomization.yaml | 1 + ...bpfman.io_v1alpha1_tcx_pass_tcprogram.yaml | 25 ++ .../apis/v1alpha1/expansion_generated.go | 4 + pkg/client/apis/v1alpha1/tcxprogram.go | 68 ++++ .../typed/apis/v1alpha1/apis_client.go | 5 + .../apis/v1alpha1/fake/fake_apis_client.go | 4 + .../apis/v1alpha1/fake/fake_tcxprogram.go | 132 +++++++ .../apis/v1alpha1/generated_expansion.go | 2 + .../typed/apis/v1alpha1/tcxprogram.go | 184 +++++++++ .../apis/v1alpha1/interface.go | 7 + .../apis/v1alpha1/tcxprogram.go | 89 +++++ pkg/client/externalversions/generic.go | 2 + 22 files changed, 1524 insertions(+), 71 deletions(-) create mode 100644 apis/v1alpha1/tcxProgram_types.go create mode 100644 bundle/manifests/bpfman.io_tcxprograms.yaml create mode 100644 config/crd/bases/bpfman.io_tcxprograms.yaml create mode 100644 config/samples/bpfman.io_v1alpha1_tcx_pass_tcprogram.yaml create mode 100644 pkg/client/apis/v1alpha1/tcxprogram.go create mode 100644 pkg/client/clientset/typed/apis/v1alpha1/fake/fake_tcxprogram.go create mode 100644 pkg/client/clientset/typed/apis/v1alpha1/tcxprogram.go create mode 100644 pkg/client/externalversions/apis/v1alpha1/tcxprogram.go diff --git a/PROJECT b/PROJECT index f4d69833a..fea9a3abf 100644 --- a/PROJECT +++ b/PROJECT @@ -33,6 +33,13 @@ resources: kind: TcProgram path: github.com/bpfman/bpfman-operator/apis/v1alpha1 version: v1alpha1 + - api: + crdVersion: v1 + controller: true + domain: bpfman.io + kind: TcxProgram + path: github.com/bpfman/bpfman-operator/apis/v1alpha1 + version: v1alpha1 - api: crdVersion: v1 controller: true diff --git a/apis/v1alpha1/bpfapplication_types.go b/apis/v1alpha1/bpfapplication_types.go index 6b28064cd..47360ca0c 100644 --- a/apis/v1alpha1/bpfapplication_types.go +++ b/apis/v1alpha1/bpfapplication_types.go @@ -84,10 +84,10 @@ type BpfApplicationProgram struct { // +optional TC *TcProgramInfo `json:"tc,omitempty"` - // tcx defines the desired state of the application's TcPrograms. + // tcx defines the desired state of the application's TcxPrograms. // +unionMember // +optional - TCX *TcProgramInfo `json:"tcx,omitempty"` + TCX *TcxProgramInfo `json:"tcx,omitempty"` // fentry defines the desired state of the application's FentryPrograms. // +unionMember diff --git a/apis/v1alpha1/tcxProgram_types.go b/apis/v1alpha1/tcxProgram_types.go new file mode 100644 index 000000000..5be918d4a --- /dev/null +++ b/apis/v1alpha1/tcxProgram_types.go @@ -0,0 +1,109 @@ +/* +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. +*/ + +// All fields are required unless explicitly marked optional +// +kubebuilder:validation:Required +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:nonNamespaced +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:resource:scope=Cluster + +// TcxProgram is the Schema for the TcxProgram API +// +kubebuilder:printcolumn:name="BpfFunctionName",type=string,JSONPath=`.spec.bpffunctionname` +// +kubebuilder:printcolumn:name="NodeSelector",type=string,JSONPath=`.spec.nodeselector` +// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[0].reason` +// +kubebuilder:printcolumn:name="Direction",type=string,JSONPath=`.spec.direction`,priority=1 +// +kubebuilder:printcolumn:name="InterfaceSelector",type=string,JSONPath=`.spec.interfaceselector`,priority=1 +// +kubebuilder:printcolumn:name="Position",type=string,JSONPath=`.spec.position`,priority=1 +type TcxProgram struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec TcxProgramSpec `json:"spec"` + // +optional + Status TcxProgramStatus `json:"status,omitempty"` +} + +// TcxProgramSpec defines the desired state of TcxProgram +type TcxProgramSpec struct { + TcxProgramInfo `json:",inline"` + BpfAppCommon `json:",inline"` +} + +// TCXPositionType defines the TCX position string +type TCXPositionType string + +const ( + // TCXFirst TCX program will be the first program to execute. + TCXFirst TCXPositionType = "First" + + // TCXLast TCX program will be the last program to execute. + TCXLast TCXPositionType = "Last" + + // TCXBefore TCX program will be before a specific TCX program + TCXBefore TCXPositionType = "Before" + + // TCXAfter TCX program will be after a specific TCX program + TCXAfter TCXPositionType = "After" +) + +// TcxProgramInfo defines the tc program details +type TcxProgramInfo struct { + BpfProgramCommon `json:",inline"` + + // Selector to determine the network interface (or interfaces) + InterfaceSelector InterfaceSelector `json:"interfaceselector"` + + // Direction specifies the direction of traffic the tcx program should + // attach to for a given network device. + // +kubebuilder:validation:Enum=ingress;egress + Direction string `json:"direction"` + + // TargetProgramName defined the existing TCX program that will be used in case we need set this TCX program + // priority against. + //+optional + TargetProgramName string `json:"targetprogramname,omitempty"` + + // Position defines the order of the TCX relative to other TCX attached to the same interface + // +kubebuilder:validation:Enum:="First";"Last";"Before";"After" + //+kubebuilder:default:=Last + //+optional + Position TCXPositionType `json:"position,omitempty"` + + // ExpectedRevision Attach TCX hook only if the expected revision matches. + //+optional + ExpectedRevision uint64 `json:"expectedRevision,omitempty"` +} + +// TcxProgramStatus defines the observed state of TcProgram +type TcxProgramStatus struct { + BpfProgramStatusCommon `json:",inline"` +} + +// +kubebuilder:object:root=true +// TcxProgramList contains a list of TcxPrograms +type TcxProgramList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TcxProgram `json:"items"` +} diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index f2e712ba1..80f3b52cd 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -132,7 +132,7 @@ func (in *BpfApplicationProgram) DeepCopyInto(out *BpfApplicationProgram) { } if in.TCX != nil { in, out := &in.TCX, &out.TCX - *out = new(TcProgramInfo) + *out = new(TcxProgramInfo) (*in).DeepCopyInto(*out) } if in.Fentry != nil { @@ -907,6 +907,115 @@ func (in *TcProgramStatus) DeepCopy() *TcProgramStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TcxProgram) DeepCopyInto(out *TcxProgram) { + *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 TcxProgram. +func (in *TcxProgram) DeepCopy() *TcxProgram { + if in == nil { + return nil + } + out := new(TcxProgram) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TcxProgram) 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 *TcxProgramInfo) DeepCopyInto(out *TcxProgramInfo) { + *out = *in + in.BpfProgramCommon.DeepCopyInto(&out.BpfProgramCommon) + in.InterfaceSelector.DeepCopyInto(&out.InterfaceSelector) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcxProgramInfo. +func (in *TcxProgramInfo) DeepCopy() *TcxProgramInfo { + if in == nil { + return nil + } + out := new(TcxProgramInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TcxProgramList) DeepCopyInto(out *TcxProgramList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TcxProgram, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcxProgramList. +func (in *TcxProgramList) DeepCopy() *TcxProgramList { + if in == nil { + return nil + } + out := new(TcxProgramList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TcxProgramList) 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 *TcxProgramSpec) DeepCopyInto(out *TcxProgramSpec) { + *out = *in + in.TcxProgramInfo.DeepCopyInto(&out.TcxProgramInfo) + in.BpfAppCommon.DeepCopyInto(&out.BpfAppCommon) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TcxProgramSpec. +func (in *TcxProgramSpec) DeepCopy() *TcxProgramSpec { + if in == nil { + return nil + } + out := new(TcxProgramSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TcxProgramStatus) DeepCopyInto(out *TcxProgramStatus) { + *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 { + if in == nil { + return nil + } + out := new(TcxProgramStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TracepointProgram) DeepCopyInto(out *TracepointProgram) { *out = *in diff --git a/apis/v1alpha1/zz_generated.register.go b/apis/v1alpha1/zz_generated.register.go index 3d3ad9e37..5b55645af 100644 --- a/apis/v1alpha1/zz_generated.register.go +++ b/apis/v1alpha1/zz_generated.register.go @@ -73,6 +73,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &KprobeProgramList{}, &TcProgram{}, &TcProgramList{}, + &TcxProgram{}, + &TcxProgramList{}, &TracepointProgram{}, &TracepointProgramList{}, &UprobeProgram{}, diff --git a/bundle/manifests/bpfman-operator.clusterserviceversion.yaml b/bundle/manifests/bpfman-operator.clusterserviceversion.yaml index 2329c26ea..b51f05364 100644 --- a/bundle/manifests/bpfman-operator.clusterserviceversion.yaml +++ b/bundle/manifests/bpfman-operator.clusterserviceversion.yaml @@ -371,6 +371,9 @@ spec: kind: TcProgram name: tcprograms.bpfman.io version: v1alpha1 + - kind: TcxProgram + name: tcxprograms.bpfman.io + version: v1alpha1 - description: TracepointProgram is the Schema for the Tracepointprograms API displayName: Tracepoint Program kind: TracepointProgram diff --git a/bundle/manifests/bpfman.io_bpfapplications.yaml b/bundle/manifests/bpfman.io_bpfapplications.yaml index df54bbf6c..6ec250127 100644 --- a/bundle/manifests/bpfman.io_bpfapplications.yaml +++ b/bundle/manifests/bpfman.io_bpfapplications.yaml @@ -575,7 +575,7 @@ spec: type: object tcx: description: tcx defines the desired state of the application's - TcPrograms. + TcxPrograms. properties: bpffunctionname: description: |- @@ -584,12 +584,17 @@ spec: type: string direction: description: |- - Direction specifies the direction of traffic the tc program should + Direction specifies the direction of traffic the tcx program should attach to for a given network device. enum: - ingress - egress type: string + expectedRevision: + description: ExpectedRevision Attach TCX hook only if the + expected revision matches. + format: int64 + type: integer interfaceselector: description: Selector to determine the network interface (or interfaces) @@ -658,43 +663,25 @@ 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 + position: + default: Last + description: Position defines the order of the TCX relative + to other TCX attached to the same interface + enum: + - First + - Last + - Before + - After + type: string + targetprogramname: 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 + TargetProgramName defined the existing TCX program that will be used in case we need set this TCX program + priority against. + type: string required: - bpffunctionname - direction - interfaceselector - - priority type: object tracepoint: description: tracepoint defines the desired state of the application's diff --git a/bundle/manifests/bpfman.io_tcxprograms.yaml b/bundle/manifests/bpfman.io_tcxprograms.yaml new file mode 100644 index 000000000..72045f463 --- /dev/null +++ b/bundle/manifests/bpfman.io_tcxprograms.yaml @@ -0,0 +1,366 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + creationTimestamp: null + name: tcxprograms.bpfman.io +spec: + group: bpfman.io + names: + kind: TcxProgram + listKind: TcxProgramList + plural: tcxprograms + singular: tcxprogram + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.bpffunctionname + name: BpfFunctionName + type: string + - jsonPath: .spec.nodeselector + name: NodeSelector + type: string + - jsonPath: .status.conditions[0].reason + name: Status + type: string + - jsonPath: .spec.direction + name: Direction + priority: 1 + type: string + - jsonPath: .spec.interfaceselector + name: InterfaceSelector + priority: 1 + type: string + - jsonPath: .spec.position + name: Position + priority: 1 + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: TcxProgram is the Schema for the TcxProgram 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: TcxProgramSpec defines the desired state of TcxProgram + properties: + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + bytecode: + description: |- + Bytecode configures where the bpf program's bytecode should be loaded + from. + properties: + image: + description: Image used to specify a bytecode container image. + properties: + imagepullpolicy: + default: IfNotPresent + description: PullPolicy describes a policy for if/when to + pull a bytecode image. Defaults to IfNotPresent. + enum: + - Always + - Never + - IfNotPresent + type: string + imagepullsecret: + description: |- + ImagePullSecret is the name of the secret bpfman should use to get remote image + repository secrets. + properties: + name: + description: Name of the secret which contains the credentials + to access the image repository. + type: string + namespace: + description: Namespace of the secret which contains the + credentials to access the image repository. + type: string + required: + - name + - namespace + type: object + url: + description: Valid container image URL used to reference a + remote bytecode image. + type: string + required: + - url + type: object + path: + description: Path is used to specify a bytecode object via filepath. + type: string + 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 + expectedRevision: + description: ExpectedRevision Attach TCX hook only if the expected + revision matches. + format: int64 + type: integer + globaldata: + additionalProperties: + format: byte + type: string + description: |- + GlobalData allows the user to set global variables when the program is loaded + with an array of raw bytes. This is a very low level primitive. The caller + 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 + will share a map with. The value is a label applied to the BpfProgram 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 + bpf program to. This field must be specified, to select all nodes + 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 + position: + default: Last + description: Position defines the order of the TCX relative to other + TCX attached to the same interface + enum: + - First + - Last + - Before + - After + type: string + targetprogramname: + description: |- + TargetProgramName defined the existing TCX program that will be used in case we need set this TCX program + priority against. + type: string + required: + - bpffunctionname + - bytecode + - direction + - interfaceselector + - nodeselector + type: object + status: + description: TcxProgramStatus defines the observed state of TcProgram + properties: + conditions: + description: |- + Conditions houses the global cluster state for the eBPFProgram. The explicit + condition types are defined internally. + 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 + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/config/crd/bases/bpfman.io_bpfapplications.yaml b/config/crd/bases/bpfman.io_bpfapplications.yaml index 845d51f86..3bebff8ac 100644 --- a/config/crd/bases/bpfman.io_bpfapplications.yaml +++ b/config/crd/bases/bpfman.io_bpfapplications.yaml @@ -575,7 +575,7 @@ spec: type: object tcx: description: tcx defines the desired state of the application's - TcPrograms. + TcxPrograms. properties: bpffunctionname: description: |- @@ -584,12 +584,17 @@ spec: type: string direction: description: |- - Direction specifies the direction of traffic the tc program should + Direction specifies the direction of traffic the tcx program should attach to for a given network device. enum: - ingress - egress type: string + expectedRevision: + description: ExpectedRevision Attach TCX hook only if the + expected revision matches. + format: int64 + type: integer interfaceselector: description: Selector to determine the network interface (or interfaces) @@ -658,43 +663,25 @@ 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 + position: + default: Last + description: Position defines the order of the TCX relative + to other TCX attached to the same interface + enum: + - First + - Last + - Before + - After + type: string + targetprogramname: 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 + TargetProgramName defined the existing TCX program that will be used in case we need set this TCX program + priority against. + type: string required: - bpffunctionname - direction - interfaceselector - - priority type: object tracepoint: description: tracepoint defines the desired state of the application's diff --git a/config/crd/bases/bpfman.io_tcxprograms.yaml b/config/crd/bases/bpfman.io_tcxprograms.yaml new file mode 100644 index 000000000..f69235212 --- /dev/null +++ b/config/crd/bases/bpfman.io_tcxprograms.yaml @@ -0,0 +1,360 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: tcxprograms.bpfman.io +spec: + group: bpfman.io + names: + kind: TcxProgram + listKind: TcxProgramList + plural: tcxprograms + singular: tcxprogram + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.bpffunctionname + name: BpfFunctionName + type: string + - jsonPath: .spec.nodeselector + name: NodeSelector + type: string + - jsonPath: .status.conditions[0].reason + name: Status + type: string + - jsonPath: .spec.direction + name: Direction + priority: 1 + type: string + - jsonPath: .spec.interfaceselector + name: InterfaceSelector + priority: 1 + type: string + - jsonPath: .spec.position + name: Position + priority: 1 + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: TcxProgram is the Schema for the TcxProgram 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: TcxProgramSpec defines the desired state of TcxProgram + properties: + bpffunctionname: + description: |- + BpfFunctionName is the name of the function that is the entry point for the BPF + program + type: string + bytecode: + description: |- + Bytecode configures where the bpf program's bytecode should be loaded + from. + properties: + image: + description: Image used to specify a bytecode container image. + properties: + imagepullpolicy: + default: IfNotPresent + description: PullPolicy describes a policy for if/when to + pull a bytecode image. Defaults to IfNotPresent. + enum: + - Always + - Never + - IfNotPresent + type: string + imagepullsecret: + description: |- + ImagePullSecret is the name of the secret bpfman should use to get remote image + repository secrets. + properties: + name: + description: Name of the secret which contains the credentials + to access the image repository. + type: string + namespace: + description: Namespace of the secret which contains the + credentials to access the image repository. + type: string + required: + - name + - namespace + type: object + url: + description: Valid container image URL used to reference a + remote bytecode image. + type: string + required: + - url + type: object + path: + description: Path is used to specify a bytecode object via filepath. + type: string + 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 + expectedRevision: + description: ExpectedRevision Attach TCX hook only if the expected + revision matches. + format: int64 + type: integer + globaldata: + additionalProperties: + format: byte + type: string + description: |- + GlobalData allows the user to set global variables when the program is loaded + with an array of raw bytes. This is a very low level primitive. The caller + 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 + will share a map with. The value is a label applied to the BpfProgram 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 + bpf program to. This field must be specified, to select all nodes + 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 + position: + default: Last + description: Position defines the order of the TCX relative to other + TCX attached to the same interface + enum: + - First + - Last + - Before + - After + type: string + targetprogramname: + description: |- + TargetProgramName defined the existing TCX program that will be used in case we need set this TCX program + priority against. + type: string + required: + - bpffunctionname + - bytecode + - direction + - interfaceselector + - nodeselector + type: object + status: + description: TcxProgramStatus defines the observed state of TcProgram + properties: + conditions: + description: |- + Conditions houses the global cluster state for the eBPFProgram. The explicit + condition types are defined internally. + 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 + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index e70f0d3ea..41da2bb50 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -4,6 +4,7 @@ resources: - bases/bpfman.io_bpfprograms.yaml - bases/bpfman.io_tcprograms.yaml + - bases/bpfman.io_tcxprograms.yaml - bases/bpfman.io_tracepointprograms.yaml - bases/bpfman.io_xdpprograms.yaml - bases/bpfman.io_kprobeprograms.yaml diff --git a/config/samples/bpfman.io_v1alpha1_tcx_pass_tcprogram.yaml b/config/samples/bpfman.io_v1alpha1_tcx_pass_tcprogram.yaml new file mode 100644 index 000000000..b865f0d1f --- /dev/null +++ b/config/samples/bpfman.io_v1alpha1_tcx_pass_tcprogram.yaml @@ -0,0 +1,25 @@ +apiVersion: bpfman.io/v1alpha1 +kind: TcxProgram +metadata: + labels: + app.kubernetes.io/name: tcxprogram + name: tcx-pass-all-nodes +spec: + bpffunctionname: pass + # Select all nodes + nodeselector: {} + interfaceselector: + primarynodeinterface: true + priority: 0 + direction: ingress + bytecode: + image: + url: quay.io/bpfman-bytecode/tc_pass:latest + globaldata: + GLOBAL_u8: + - 0x01 + GLOBAL_u32: + - 0x0D + - 0x0C + - 0x0B + - 0x0A diff --git a/pkg/client/apis/v1alpha1/expansion_generated.go b/pkg/client/apis/v1alpha1/expansion_generated.go index 7c31cea1b..df6e451bd 100644 --- a/pkg/client/apis/v1alpha1/expansion_generated.go +++ b/pkg/client/apis/v1alpha1/expansion_generated.go @@ -42,6 +42,10 @@ type KprobeProgramListerExpansion interface{} // TcProgramLister. type TcProgramListerExpansion interface{} +// TcxProgramListerExpansion allows custom methods to be added to +// TcxProgramLister. +type TcxProgramListerExpansion interface{} + // TracepointProgramListerExpansion allows custom methods to be added to // TracepointProgramLister. type TracepointProgramListerExpansion interface{} diff --git a/pkg/client/apis/v1alpha1/tcxprogram.go b/pkg/client/apis/v1alpha1/tcxprogram.go new file mode 100644 index 000000000..c65dfd8b5 --- /dev/null +++ b/pkg/client/apis/v1alpha1/tcxprogram.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" +) + +// TcxProgramLister helps list TcxPrograms. +// All objects returned here must be treated as read-only. +type TcxProgramLister interface { + // List lists all TcxPrograms in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.TcxProgram, err error) + // Get retrieves the TcxProgram from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.TcxProgram, error) + TcxProgramListerExpansion +} + +// tcxProgramLister implements the TcxProgramLister interface. +type tcxProgramLister struct { + indexer cache.Indexer +} + +// NewTcxProgramLister returns a new TcxProgramLister. +func NewTcxProgramLister(indexer cache.Indexer) TcxProgramLister { + return &tcxProgramLister{indexer: indexer} +} + +// List lists all TcxPrograms in the indexer. +func (s *tcxProgramLister) List(selector labels.Selector) (ret []*v1alpha1.TcxProgram, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.TcxProgram)) + }) + return ret, err +} + +// Get retrieves the TcxProgram from the index for a given name. +func (s *tcxProgramLister) Get(name string) (*v1alpha1.TcxProgram, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("tcxprogram"), name) + } + return obj.(*v1alpha1.TcxProgram), nil +} diff --git a/pkg/client/clientset/typed/apis/v1alpha1/apis_client.go b/pkg/client/clientset/typed/apis/v1alpha1/apis_client.go index c1d54ecdd..ac2e4d3a1 100644 --- a/pkg/client/clientset/typed/apis/v1alpha1/apis_client.go +++ b/pkg/client/clientset/typed/apis/v1alpha1/apis_client.go @@ -34,6 +34,7 @@ type BpfmanV1alpha1Interface interface { FexitProgramsGetter KprobeProgramsGetter TcProgramsGetter + TcxProgramsGetter TracepointProgramsGetter UprobeProgramsGetter XdpProgramsGetter @@ -68,6 +69,10 @@ func (c *BpfmanV1alpha1Client) TcPrograms() TcProgramInterface { return newTcPrograms(c) } +func (c *BpfmanV1alpha1Client) TcxPrograms() TcxProgramInterface { + return newTcxPrograms(c) +} + func (c *BpfmanV1alpha1Client) TracepointPrograms() TracepointProgramInterface { return newTracepointPrograms(c) } 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 7acfcffc8..b83fbca87 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 @@ -52,6 +52,10 @@ func (c *FakeBpfmanV1alpha1) TcPrograms() v1alpha1.TcProgramInterface { return &FakeTcPrograms{c} } +func (c *FakeBpfmanV1alpha1) TcxPrograms() v1alpha1.TcxProgramInterface { + return &FakeTcxPrograms{c} +} + func (c *FakeBpfmanV1alpha1) TracepointPrograms() v1alpha1.TracepointProgramInterface { return &FakeTracepointPrograms{c} } diff --git a/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_tcxprogram.go b/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_tcxprogram.go new file mode 100644 index 000000000..24df1d922 --- /dev/null +++ b/pkg/client/clientset/typed/apis/v1alpha1/fake/fake_tcxprogram.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" +) + +// FakeTcxPrograms implements TcxProgramInterface +type FakeTcxPrograms struct { + Fake *FakeBpfmanV1alpha1 +} + +var tcxprogramsResource = v1alpha1.SchemeGroupVersion.WithResource("tcxprograms") + +var tcxprogramsKind = v1alpha1.SchemeGroupVersion.WithKind("TcxProgram") + +// Get takes name of the tcxProgram, and returns the corresponding tcxProgram object, and an error if there is any. +func (c *FakeTcxPrograms) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.TcxProgram, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(tcxprogramsResource, name), &v1alpha1.TcxProgram{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.TcxProgram), err +} + +// List takes label and field selectors, and returns the list of TcxPrograms that match those selectors. +func (c *FakeTcxPrograms) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.TcxProgramList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(tcxprogramsResource, tcxprogramsKind, opts), &v1alpha1.TcxProgramList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.TcxProgramList{ListMeta: obj.(*v1alpha1.TcxProgramList).ListMeta} + for _, item := range obj.(*v1alpha1.TcxProgramList).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 tcxPrograms. +func (c *FakeTcxPrograms) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(tcxprogramsResource, opts)) +} + +// Create takes the representation of a tcxProgram and creates it. Returns the server's representation of the tcxProgram, and an error, if there is any. +func (c *FakeTcxPrograms) Create(ctx context.Context, tcxProgram *v1alpha1.TcxProgram, opts v1.CreateOptions) (result *v1alpha1.TcxProgram, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(tcxprogramsResource, tcxProgram), &v1alpha1.TcxProgram{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.TcxProgram), err +} + +// Update takes the representation of a tcxProgram and updates it. Returns the server's representation of the tcxProgram, and an error, if there is any. +func (c *FakeTcxPrograms) Update(ctx context.Context, tcxProgram *v1alpha1.TcxProgram, opts v1.UpdateOptions) (result *v1alpha1.TcxProgram, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(tcxprogramsResource, tcxProgram), &v1alpha1.TcxProgram{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.TcxProgram), 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 *FakeTcxPrograms) UpdateStatus(ctx context.Context, tcxProgram *v1alpha1.TcxProgram, opts v1.UpdateOptions) (*v1alpha1.TcxProgram, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(tcxprogramsResource, "status", tcxProgram), &v1alpha1.TcxProgram{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.TcxProgram), err +} + +// Delete takes name of the tcxProgram and deletes it. Returns an error if one occurs. +func (c *FakeTcxPrograms) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(tcxprogramsResource, name, opts), &v1alpha1.TcxProgram{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTcxPrograms) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(tcxprogramsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.TcxProgramList{}) + return err +} + +// Patch applies the patch and returns the patched tcxProgram. +func (c *FakeTcxPrograms) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.TcxProgram, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(tcxprogramsResource, name, pt, data, subresources...), &v1alpha1.TcxProgram{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.TcxProgram), err +} diff --git a/pkg/client/clientset/typed/apis/v1alpha1/generated_expansion.go b/pkg/client/clientset/typed/apis/v1alpha1/generated_expansion.go index 6c297eeee..c514790d0 100644 --- a/pkg/client/clientset/typed/apis/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/typed/apis/v1alpha1/generated_expansion.go @@ -30,6 +30,8 @@ type KprobeProgramExpansion interface{} type TcProgramExpansion interface{} +type TcxProgramExpansion interface{} + type TracepointProgramExpansion interface{} type UprobeProgramExpansion interface{} diff --git a/pkg/client/clientset/typed/apis/v1alpha1/tcxprogram.go b/pkg/client/clientset/typed/apis/v1alpha1/tcxprogram.go new file mode 100644 index 000000000..8363b99d8 --- /dev/null +++ b/pkg/client/clientset/typed/apis/v1alpha1/tcxprogram.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" +) + +// TcxProgramsGetter has a method to return a TcxProgramInterface. +// A group's client should implement this interface. +type TcxProgramsGetter interface { + TcxPrograms() TcxProgramInterface +} + +// TcxProgramInterface has methods to work with TcxProgram resources. +type TcxProgramInterface interface { + Create(ctx context.Context, tcxProgram *v1alpha1.TcxProgram, opts v1.CreateOptions) (*v1alpha1.TcxProgram, error) + Update(ctx context.Context, tcxProgram *v1alpha1.TcxProgram, opts v1.UpdateOptions) (*v1alpha1.TcxProgram, error) + UpdateStatus(ctx context.Context, tcxProgram *v1alpha1.TcxProgram, opts v1.UpdateOptions) (*v1alpha1.TcxProgram, 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.TcxProgram, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.TcxProgramList, 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.TcxProgram, err error) + TcxProgramExpansion +} + +// tcxPrograms implements TcxProgramInterface +type tcxPrograms struct { + client rest.Interface +} + +// newTcxPrograms returns a TcxPrograms +func newTcxPrograms(c *BpfmanV1alpha1Client) *tcxPrograms { + return &tcxPrograms{ + client: c.RESTClient(), + } +} + +// Get takes name of the tcxProgram, and returns the corresponding tcxProgram object, and an error if there is any. +func (c *tcxPrograms) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.TcxProgram, err error) { + result = &v1alpha1.TcxProgram{} + err = c.client.Get(). + Resource("tcxprograms"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TcxPrograms that match those selectors. +func (c *tcxPrograms) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.TcxProgramList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.TcxProgramList{} + err = c.client.Get(). + Resource("tcxprograms"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested tcxPrograms. +func (c *tcxPrograms) 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("tcxprograms"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a tcxProgram and creates it. Returns the server's representation of the tcxProgram, and an error, if there is any. +func (c *tcxPrograms) Create(ctx context.Context, tcxProgram *v1alpha1.TcxProgram, opts v1.CreateOptions) (result *v1alpha1.TcxProgram, err error) { + result = &v1alpha1.TcxProgram{} + err = c.client.Post(). + Resource("tcxprograms"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(tcxProgram). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a tcxProgram and updates it. Returns the server's representation of the tcxProgram, and an error, if there is any. +func (c *tcxPrograms) Update(ctx context.Context, tcxProgram *v1alpha1.TcxProgram, opts v1.UpdateOptions) (result *v1alpha1.TcxProgram, err error) { + result = &v1alpha1.TcxProgram{} + err = c.client.Put(). + Resource("tcxprograms"). + Name(tcxProgram.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(tcxProgram). + 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 *tcxPrograms) UpdateStatus(ctx context.Context, tcxProgram *v1alpha1.TcxProgram, opts v1.UpdateOptions) (result *v1alpha1.TcxProgram, err error) { + result = &v1alpha1.TcxProgram{} + err = c.client.Put(). + Resource("tcxprograms"). + Name(tcxProgram.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(tcxProgram). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the tcxProgram and deletes it. Returns an error if one occurs. +func (c *tcxPrograms) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("tcxprograms"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *tcxPrograms) 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("tcxprograms"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched tcxProgram. +func (c *tcxPrograms) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.TcxProgram, err error) { + result = &v1alpha1.TcxProgram{} + err = c.client.Patch(pt). + Resource("tcxprograms"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/externalversions/apis/v1alpha1/interface.go b/pkg/client/externalversions/apis/v1alpha1/interface.go index 0b792e2fe..432597f9d 100644 --- a/pkg/client/externalversions/apis/v1alpha1/interface.go +++ b/pkg/client/externalversions/apis/v1alpha1/interface.go @@ -36,6 +36,8 @@ type Interface interface { KprobePrograms() KprobeProgramInformer // TcPrograms returns a TcProgramInformer. TcPrograms() TcProgramInformer + // TcxPrograms returns a TcxProgramInformer. + TcxPrograms() TcxProgramInformer // TracepointPrograms returns a TracepointProgramInformer. TracepointPrograms() TracepointProgramInformer // UprobePrograms returns a UprobeProgramInformer. @@ -85,6 +87,11 @@ func (v *version) TcPrograms() TcProgramInformer { return &tcProgramInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } +// TcxPrograms returns a TcxProgramInformer. +func (v *version) TcxPrograms() TcxProgramInformer { + return &tcxProgramInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + // TracepointPrograms returns a TracepointProgramInformer. func (v *version) TracepointPrograms() TracepointProgramInformer { return &tracepointProgramInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/externalversions/apis/v1alpha1/tcxprogram.go b/pkg/client/externalversions/apis/v1alpha1/tcxprogram.go new file mode 100644 index 000000000..ca8fdaadc --- /dev/null +++ b/pkg/client/externalversions/apis/v1alpha1/tcxprogram.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" +) + +// TcxProgramInformer provides access to a shared informer and lister for +// TcxPrograms. +type TcxProgramInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.TcxProgramLister +} + +type tcxProgramInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewTcxProgramInformer constructs a new informer for TcxProgram 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 NewTcxProgramInformer(client clientset.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTcxProgramInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredTcxProgramInformer constructs a new informer for TcxProgram 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 NewFilteredTcxProgramInformer(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().TcxPrograms().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.BpfmanV1alpha1().TcxPrograms().Watch(context.TODO(), options) + }, + }, + &apisv1alpha1.TcxProgram{}, + resyncPeriod, + indexers, + ) +} + +func (f *tcxProgramInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTcxProgramInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *tcxProgramInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisv1alpha1.TcxProgram{}, f.defaultInformer) +} + +func (f *tcxProgramInformer) Lister() v1alpha1.TcxProgramLister { + return v1alpha1.NewTcxProgramLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/externalversions/generic.go b/pkg/client/externalversions/generic.go index e045549cf..4db1e4a1e 100644 --- a/pkg/client/externalversions/generic.go +++ b/pkg/client/externalversions/generic.go @@ -65,6 +65,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Bpfman().V1alpha1().KprobePrograms().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("tcprograms"): return &genericInformer{resource: resource.GroupResource(), informer: f.Bpfman().V1alpha1().TcPrograms().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("tcxprograms"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Bpfman().V1alpha1().TcxPrograms().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("tracepointprograms"): return &genericInformer{resource: resource.GroupResource(), informer: f.Bpfman().V1alpha1().TracepointPrograms().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("uprobeprograms"): From 0d7718c5fb6caee728965e348e2528b3ec391148 Mon Sep 17 00:00:00 2001 From: Mohamed Mahmoud Date: Tue, 13 Aug 2024 18:08:01 -0400 Subject: [PATCH 2/8] Add controllers for TCX Signed-off-by: Mohamed Mahmoud --- apis/v1alpha1/tcxProgram_types.go | 37 +- ...c.authorization.k8s.io_v1_clusterrole.yaml | 14 + ...bpfman-operator.clusterserviceversion.yaml | 28 +- .../manifests/bpfman.io_bpfapplications.yaml | 28 +- bundle/manifests/bpfman.io_tcxprograms.yaml | 28 +- cmd/bpfman-agent/main.go | 7 + cmd/bpfman-operator/main.go | 7 + .../crd/bases/bpfman.io_bpfapplications.yaml | 28 +- config/crd/bases/bpfman.io_tcxprograms.yaml | 28 +- config/rbac/bpfman-agent/role.yaml | 14 + config/rbac/bpfman-operator/role.yaml | 26 + .../bpfman-agent/application-program.go | 31 +- controllers/bpfman-agent/common.go | 1 + controllers/bpfman-agent/tcx-program.go | 223 ++++++++ controllers/bpfman-agent/tcx-program_test.go | 476 ++++++++++++++++++ controllers/bpfman-operator/tcx-program.go | 114 +++++ .../bpfman-operator/tcx-program_test.go | 161 ++++++ internal/constants.go | 5 + 18 files changed, 1146 insertions(+), 110 deletions(-) create mode 100644 controllers/bpfman-agent/tcx-program.go create mode 100644 controllers/bpfman-agent/tcx-program_test.go create mode 100644 controllers/bpfman-operator/tcx-program.go create mode 100644 controllers/bpfman-operator/tcx-program_test.go diff --git a/apis/v1alpha1/tcxProgram_types.go b/apis/v1alpha1/tcxProgram_types.go index 5be918d4a..31f2b223e 100644 --- a/apis/v1alpha1/tcxProgram_types.go +++ b/apis/v1alpha1/tcxProgram_types.go @@ -50,23 +50,6 @@ type TcxProgramSpec struct { BpfAppCommon `json:",inline"` } -// TCXPositionType defines the TCX position string -type TCXPositionType string - -const ( - // TCXFirst TCX program will be the first program to execute. - TCXFirst TCXPositionType = "First" - - // TCXLast TCX program will be the last program to execute. - TCXLast TCXPositionType = "Last" - - // TCXBefore TCX program will be before a specific TCX program - TCXBefore TCXPositionType = "Before" - - // TCXAfter TCX program will be after a specific TCX program - TCXAfter TCXPositionType = "After" -) - // TcxProgramInfo defines the tc program details type TcxProgramInfo struct { BpfProgramCommon `json:",inline"` @@ -79,20 +62,12 @@ type TcxProgramInfo struct { // +kubebuilder:validation:Enum=ingress;egress Direction string `json:"direction"` - // TargetProgramName defined the existing TCX program that will be used in case we need set this TCX program - // priority against. - //+optional - TargetProgramName string `json:"targetprogramname,omitempty"` - - // Position defines the order of the TCX relative to other TCX attached to the same interface - // +kubebuilder:validation:Enum:="First";"Last";"Before";"After" - //+kubebuilder:default:=Last - //+optional - Position TCXPositionType `json:"position,omitempty"` - - // ExpectedRevision Attach TCX hook only if the expected revision matches. - //+optional - ExpectedRevision uint64 `json:"expectedRevision,omitempty"` + // 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"` } // TcxProgramStatus defines the observed state of TcProgram 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 a051e457d..feb710832 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 @@ -100,6 +100,20 @@ rules: - tcprograms/finalizers verbs: - update +- apiGroups: + - bpfman.io + resources: + - tcxprograms + verbs: + - get + - list + - watch +- apiGroups: + - bpfman.io + resources: + - tcxprograms/finalizers + verbs: + - update - apiGroups: - bpfman.io resources: diff --git a/bundle/manifests/bpfman-operator.clusterserviceversion.yaml b/bundle/manifests/bpfman-operator.clusterserviceversion.yaml index b51f05364..1629a2300 100644 --- a/bundle/manifests/bpfman-operator.clusterserviceversion.yaml +++ b/bundle/manifests/bpfman-operator.clusterserviceversion.yaml @@ -296,7 +296,7 @@ metadata: capabilities: Basic Install categories: OpenShift Optional containerImage: quay.io/bpfman/bpfman-operator:latest - createdAt: "2024-10-17T13:56:37Z" + createdAt: "2024-10-21T11:51:40Z" features.operators.openshift.io/cnf: "false" features.operators.openshift.io/cni: "false" features.operators.openshift.io/csi: "true" @@ -866,6 +866,32 @@ spec: - get - patch - update + - apiGroups: + - bpfman.io + resources: + - tcxprograms + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - bpfman.io + resources: + - tcxprograms/finalizers + verbs: + - update + - apiGroups: + - bpfman.io + resources: + - tcxprograms/status + verbs: + - get + - patch + - update - apiGroups: - bpfman.io resources: diff --git a/bundle/manifests/bpfman.io_bpfapplications.yaml b/bundle/manifests/bpfman.io_bpfapplications.yaml index 6ec250127..4f6a53fdd 100644 --- a/bundle/manifests/bpfman.io_bpfapplications.yaml +++ b/bundle/manifests/bpfman.io_bpfapplications.yaml @@ -590,11 +590,6 @@ spec: - ingress - egress type: string - expectedRevision: - description: ExpectedRevision Attach TCX hook only if the - expected revision matches. - format: int64 - type: integer interfaceselector: description: Selector to determine the network interface (or interfaces) @@ -663,25 +658,20 @@ spec: type: object type: object x-kubernetes-map-type: atomic - position: - default: Last - description: Position defines the order of the TCX relative - to other TCX attached to the same interface - enum: - - First - - Last - - Before - - After - type: string - targetprogramname: + priority: description: |- - TargetProgramName defined the existing TCX program that will be used in case we need set this TCX program - priority against. - type: string + 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 diff --git a/bundle/manifests/bpfman.io_tcxprograms.yaml b/bundle/manifests/bpfman.io_tcxprograms.yaml index 72045f463..4aeb98cd2 100644 --- a/bundle/manifests/bpfman.io_tcxprograms.yaml +++ b/bundle/manifests/bpfman.io_tcxprograms.yaml @@ -119,11 +119,6 @@ spec: - ingress - egress type: string - expectedRevision: - description: ExpectedRevision Attach TCX hook only if the expected - revision matches. - format: int64 - type: integer globaldata: additionalProperties: format: byte @@ -250,27 +245,22 @@ spec: type: object type: object x-kubernetes-map-type: atomic - position: - default: Last - description: Position defines the order of the TCX relative to other - TCX attached to the same interface - enum: - - First - - Last - - Before - - After - type: string - targetprogramname: + priority: description: |- - TargetProgramName defined the existing TCX program that will be used in case we need set this TCX program - priority against. - type: string + 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 - bytecode - direction - interfaceselector - nodeselector + - priority type: object status: description: TcxProgramStatus defines the observed state of TcProgram diff --git a/cmd/bpfman-agent/main.go b/cmd/bpfman-agent/main.go index b2e59d175..02f03e2c1 100644 --- a/cmd/bpfman-agent/main.go +++ b/cmd/bpfman-agent/main.go @@ -161,6 +161,13 @@ func main() { os.Exit(1) } + if err = (&bpfmanagent.TcxProgramReconciler{ + ReconcilerCommon: common, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create tcxProgram controller", "controller", "BpfProgram") + os.Exit(1) + } + if err = (&bpfmanagent.TracepointProgramReconciler{ ReconcilerCommon: common, }).SetupWithManager(mgr); err != nil { diff --git a/cmd/bpfman-operator/main.go b/cmd/bpfman-operator/main.go index 131783cd7..b6f2e86a2 100644 --- a/cmd/bpfman-operator/main.go +++ b/cmd/bpfman-operator/main.go @@ -207,6 +207,13 @@ func main() { os.Exit(1) } + if err = (&bpfmanoperator.TcxProgramReconciler{ + ReconcilerCommon: common, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create tcxProgram controller", "controller", "BpfProgram") + os.Exit(1) + } + if err = (&bpfmanoperator.TracepointProgramReconciler{ ReconcilerCommon: common, }).SetupWithManager(mgr); err != nil { diff --git a/config/crd/bases/bpfman.io_bpfapplications.yaml b/config/crd/bases/bpfman.io_bpfapplications.yaml index 3bebff8ac..9bc282ef1 100644 --- a/config/crd/bases/bpfman.io_bpfapplications.yaml +++ b/config/crd/bases/bpfman.io_bpfapplications.yaml @@ -590,11 +590,6 @@ spec: - ingress - egress type: string - expectedRevision: - description: ExpectedRevision Attach TCX hook only if the - expected revision matches. - format: int64 - type: integer interfaceselector: description: Selector to determine the network interface (or interfaces) @@ -663,25 +658,20 @@ spec: type: object type: object x-kubernetes-map-type: atomic - position: - default: Last - description: Position defines the order of the TCX relative - to other TCX attached to the same interface - enum: - - First - - Last - - Before - - After - type: string - targetprogramname: + priority: description: |- - TargetProgramName defined the existing TCX program that will be used in case we need set this TCX program - priority against. - type: string + 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 diff --git a/config/crd/bases/bpfman.io_tcxprograms.yaml b/config/crd/bases/bpfman.io_tcxprograms.yaml index f69235212..31a6d8480 100644 --- a/config/crd/bases/bpfman.io_tcxprograms.yaml +++ b/config/crd/bases/bpfman.io_tcxprograms.yaml @@ -119,11 +119,6 @@ spec: - ingress - egress type: string - expectedRevision: - description: ExpectedRevision Attach TCX hook only if the expected - revision matches. - format: int64 - type: integer globaldata: additionalProperties: format: byte @@ -250,27 +245,22 @@ spec: type: object type: object x-kubernetes-map-type: atomic - position: - default: Last - description: Position defines the order of the TCX relative to other - TCX attached to the same interface - enum: - - First - - Last - - Before - - After - type: string - targetprogramname: + priority: description: |- - TargetProgramName defined the existing TCX program that will be used in case we need set this TCX program - priority against. - type: string + 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 - bytecode - direction - interfaceselector - nodeselector + - priority type: object status: description: TcxProgramStatus defines the observed state of TcProgram diff --git a/config/rbac/bpfman-agent/role.yaml b/config/rbac/bpfman-agent/role.yaml index 4cc0e9fe9..da51037c7 100644 --- a/config/rbac/bpfman-agent/role.yaml +++ b/config/rbac/bpfman-agent/role.yaml @@ -100,6 +100,20 @@ rules: - tcprograms/finalizers verbs: - update +- apiGroups: + - bpfman.io + resources: + - tcxprograms + verbs: + - get + - list + - watch +- apiGroups: + - bpfman.io + resources: + - tcxprograms/finalizers + verbs: + - update - apiGroups: - bpfman.io resources: diff --git a/config/rbac/bpfman-operator/role.yaml b/config/rbac/bpfman-operator/role.yaml index 3a6848ce5..5e0913a4c 100644 --- a/config/rbac/bpfman-operator/role.yaml +++ b/config/rbac/bpfman-operator/role.yaml @@ -160,6 +160,32 @@ rules: - get - patch - update +- apiGroups: + - bpfman.io + resources: + - tcxprograms + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - bpfman.io + resources: + - tcxprograms/finalizers + verbs: + - update +- apiGroups: + - bpfman.io + resources: + - tcxprograms/status + verbs: + - get + - patch + - update - apiGroups: - bpfman.io resources: diff --git a/controllers/bpfman-agent/application-program.go b/controllers/bpfman-agent/application-program.go index 9691d29a8..10c21e8ad 100644 --- a/controllers/bpfman-agent/application-program.go +++ b/controllers/bpfman-agent/application-program.go @@ -189,8 +189,7 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque // Reconcile TracepointProgram. complete, res, err = r.reconcileCommon(ctx, rec, tracepointObjects) - case bpfmaniov1alpha1.ProgTypeTC, - bpfmaniov1alpha1.ProgTypeTCX: + case bpfmaniov1alpha1.ProgTypeTC: interfaces, ifErr := getInterfaces(&p.TC.InterfaceSelector, r.ourNode) if ifErr != nil { ctxLogger.Error(ifErr, "failed to get interfaces for TC Program", @@ -218,6 +217,34 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque // Reconcile TcProgram. complete, res, err = r.reconcileCommon(ctx, rec, tcObjects) + case bpfmaniov1alpha1.ProgTypeTCX: + interfaces, ifErr := getInterfaces(&p.TCX.InterfaceSelector, r.ourNode) + if ifErr != nil { + ctxLogger.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, interfaces[0]) + tcxProgram := bpfmaniov1alpha1.TcxProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildProgramName(a, p), + Labels: map[string]string{internal.AppProgramId: appProgramId}}, + Spec: bpfmaniov1alpha1.TcxProgramSpec{ + TcxProgramInfo: *p.TCX, + BpfAppCommon: a.Spec.BpfAppCommon, + }, + } + rec := &TcxProgramReconciler{ + ReconcilerCommon: r.ReconcilerCommon, + currentTcxProgram: &tcxProgram, + ourNode: r.ourNode, + } + rec.appOwner = &a + tcxObjects := []client.Object{&tcxProgram} + appProgramMap[appProgramId] = true + // Reconcile TcxProgram. + complete, res, err = r.reconcileCommon(ctx, rec, tcxObjects) + case bpfmaniov1alpha1.ProgTypeXDP: interfaces, ifErr := getInterfaces(&p.XDP.InterfaceSelector, r.ourNode) if ifErr != nil { diff --git a/controllers/bpfman-agent/common.go b/controllers/bpfman-agent/common.go index 87394ce25..1ecf239f5 100644 --- a/controllers/bpfman-agent/common.go +++ b/controllers/bpfman-agent/common.go @@ -51,6 +51,7 @@ import ( //+kubebuilder:rbac:groups=bpfman.io,resources=bpfprograms/status,verbs=get;update;patch //+kubebuilder:rbac:groups=bpfman.io,resources=bpfprograms/finalizers,verbs=update //+kubebuilder:rbac:groups=bpfman.io,resources=tcprograms/finalizers,verbs=update +//+kubebuilder:rbac:groups=bpfman.io,resources=tcxprograms/finalizers,verbs=update //+kubebuilder:rbac:groups=bpfman.io,resources=xdpprograms/finalizers,verbs=update //+kubebuilder:rbac:groups=bpfman.io,resources=tracepointprograms/finalizers,verbs=update //+kubebuilder:rbac:groups=bpfman.io,resources=kprobeprograms/finalizers,verbs=update diff --git a/controllers/bpfman-agent/tcx-program.go b/controllers/bpfman-agent/tcx-program.go new file mode 100644 index 000000000..53207f705 --- /dev/null +++ b/controllers/bpfman-agent/tcx-program.go @@ -0,0 +1,223 @@ +/* +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 bpfmanagent + +import ( + "context" + "fmt" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + bpfmanagentinternal "github.com/bpfman/bpfman-operator/controllers/bpfman-agent/internal" + "github.com/bpfman/bpfman-operator/internal" + gobpfman "github.com/bpfman/bpfman/clients/gobpfman/v1" + + 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/handler" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +//+kubebuilder:rbac:groups=bpfman.io,resources=tcxprograms,verbs=get;list;watch + +// TcxProgramReconciler reconciles a tcxProgram object by creating multiple +// bpfProgram objects and managing bpfman for each one. +type TcxProgramReconciler struct { + ReconcilerCommon + currentTcxProgram *bpfmaniov1alpha1.TcxProgram + interfaces []string + ourNode *v1.Node +} + +func (r *TcxProgramReconciler) getFinalizer() string { + return r.finalizer +} + +func (r *TcxProgramReconciler) getOwner() metav1.Object { + if r.appOwner == nil { + return r.currentTcxProgram + } else { + return r.appOwner + } +} + +func (r *TcxProgramReconciler) getRecType() string { + return r.recType +} + +func (r *TcxProgramReconciler) getProgType() internal.ProgramType { + return internal.Tc +} + +func (r *TcxProgramReconciler) getName() string { + return r.currentTcxProgram.Name +} + +func (r *TcxProgramReconciler) getNode() *v1.Node { + return r.ourNode +} + +func (r *TcxProgramReconciler) getBpfProgramCommon() *bpfmaniov1alpha1.BpfProgramCommon { + return &r.currentTcxProgram.Spec.BpfProgramCommon +} + +func (r *TcxProgramReconciler) getNodeSelector() *metav1.LabelSelector { + return &r.currentTcxProgram.Spec.NodeSelector +} + +func (r *TcxProgramReconciler) getBpfGlobalData() map[string][]byte { + return r.currentTcxProgram.Spec.GlobalData +} + +func (r *TcxProgramReconciler) getAppProgramId() string { + return appProgramId(r.currentTcxProgram.GetLabels()) +} + +func (r *TcxProgramReconciler) setCurrentProgram(program client.Object) error { + var err error + var ok bool + + r.currentTcxProgram, ok = program.(*bpfmaniov1alpha1.TcxProgram) + if !ok { + return fmt.Errorf("failed to cast program to TcxProgram") + } + + r.interfaces, err = getInterfaces(&r.currentTcxProgram.Spec.InterfaceSelector, r.ourNode) + if err != nil { + return fmt.Errorf("failed to get interfaces for TcxProgram: %v", err) + } + + return nil +} + +// SetupWithManager sets up the controller with the Manager. +// The Bpfman-Agent should reconcile whenever a TcxProgram is updated, +// load the program to the node via bpfman, and then create bpfProgram object(s) +// to reflect per node state information. +func (r *TcxProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&bpfmaniov1alpha1.TcxProgram{}, builder.WithPredicates(predicate.And( + predicate.GenerationChangedPredicate{}, + predicate.ResourceVersionChangedPredicate{}), + ), + ). + Owns(&bpfmaniov1alpha1.BpfProgram{}, + builder.WithPredicates(predicate.And( + internal.BpfProgramTypePredicate(internal.TcxString), + internal.BpfProgramNodePredicate(r.NodeName)), + ), + ). + // Only trigger reconciliation if node labels change since that could + // make the TcxProgram no longer select the Node. Additionally only + // care about events specific to our node + Watches( + &v1.Node{}, + &handler.EnqueueRequestForObject{}, + builder.WithPredicates(predicate.And(predicate.LabelChangedPredicate{}, nodePredicate(r.NodeName))), + ). + Complete(r) +} + +func (r *TcxProgramReconciler) getExpectedBpfPrograms(ctx context.Context) (*bpfmaniov1alpha1.BpfProgramList, error) { + progs := &bpfmaniov1alpha1.BpfProgramList{} + for _, iface := range r.interfaces { + attachPoint := iface + "-" + r.currentTcxProgram.Spec.Direction + annotations := map[string]string{internal.TcxProgramInterface: iface} + + 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 +} + +func (r *TcxProgramReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + // Initialize node and current program + r.currentTcxProgram = &bpfmaniov1alpha1.TcxProgram{} + r.finalizer = internal.TcxProgramControllerFinalizer + r.recType = internal.TcxString + r.ourNode = &v1.Node{} + r.Logger = ctrl.Log.WithName("tcx") + + ctxLogger := log.FromContext(ctx) + ctxLogger.Info("Reconcile TCX: Enter", "ReconcileKey", req) + + // 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) + } + + tcxPrograms := &bpfmaniov1alpha1.TcxProgramList{} + + opts := []client.ListOption{} + + if err := r.List(ctx, tcxPrograms, opts...); err != nil { + return ctrl.Result{Requeue: false}, fmt.Errorf("failed getting TcxPrograms for full reconcile %s : %v", + req.NamespacedName, err) + } + + if len(tcxPrograms.Items) == 0 { + r.Logger.Info("TcxProgramController found no TCX Programs") + return ctrl.Result{Requeue: false}, nil + } + + // Create a list of tcx programs to pass into reconcileCommon() + var tcxObjects []client.Object = make([]client.Object, len(tcxPrograms.Items)) + for i := range tcxPrograms.Items { + tcxObjects[i] = &tcxPrograms.Items[i] + } + + // Reconcile each TcxProgram. + _, result, err := r.reconcileCommon(ctx, r, tcxObjects) + return result, err +} + +func (r *TcxProgramReconciler) getLoadRequest(bpfProgram *bpfmaniov1alpha1.BpfProgram, mapOwnerId *uint32) (*gobpfman.LoadRequest, error) { + bytecode, err := bpfmanagentinternal.GetBytecode(r.Client, &r.currentTcxProgram.Spec.ByteCode) + if err != nil { + return nil, fmt.Errorf("failed to process bytecode selector: %v", err) + } + + loadRequest := gobpfman.LoadRequest{ + Bytecode: bytecode, + Name: r.currentTcxProgram.Spec.BpfFunctionName, + ProgramType: uint32(internal.Tc), + Attach: &gobpfman.AttachInfo{ + Info: &gobpfman.AttachInfo_TcAttachInfo{ + TcAttachInfo: &gobpfman.TCAttachInfo{ + Priority: r.currentTcxProgram.Spec.Priority, + Iface: bpfProgram.Annotations[internal.TcxProgramInterface], + Direction: r.currentTcxProgram.Spec.Direction, + }, + }, + }, + Metadata: map[string]string{internal.UuidMetadataKey: string(bpfProgram.UID), internal.ProgramNameKey: r.getOwner().GetName()}, + GlobalData: r.currentTcxProgram.Spec.GlobalData, + MapOwnerId: mapOwnerId, + } + + return &loadRequest, nil +} diff --git a/controllers/bpfman-agent/tcx-program_test.go b/controllers/bpfman-agent/tcx-program_test.go new file mode 100644 index 000000000..4c759343a --- /dev/null +++ b/controllers/bpfman-agent/tcx-program_test.go @@ -0,0 +1,476 @@ +/* +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 bpfmanagent + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "google.golang.org/protobuf/testing/protocmp" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + bpfmanagentinternal "github.com/bpfman/bpfman-operator/controllers/bpfman-agent/internal" + agenttestutils "github.com/bpfman/bpfman-operator/controllers/bpfman-agent/internal/test-utils" + testutils "github.com/bpfman/bpfman-operator/internal/test-utils" + + internal "github.com/bpfman/bpfman-operator/internal" + + gobpfman "github.com/bpfman/bpfman/clients/gobpfman/v1" + "github.com/stretchr/testify/require" + 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" +) + +func TestTcxProgramControllerCreate(t *testing.T) { + var ( + name = "fakeTcxProgram" + namespace = "bpfman" + bytecodePath = "/tmp/hello.o" + bpfFunctionName = "test" + direction = "ingress" + fakeNode = testutils.NewNode("fake-control-plane") + fakeInt = "eth0" + ctx = context.TODO() + appProgramId = "" + attachPoint = fakeInt + "-" + direction + bpfProg = &bpfmaniov1alpha1.BpfProgram{} + fakeUID = "ef71d42c-aa21-48e8-a697-82391d801a81" + ) + // A TcxProgram object with metadata and spec. + tcx := &bpfmaniov1alpha1.TcxProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: bpfmaniov1alpha1.TcxProgramSpec{ + BpfAppCommon: bpfmaniov1alpha1.BpfAppCommon{ + NodeSelector: metav1.LabelSelector{}, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + TcxProgramInfo: bpfmaniov1alpha1.TcxProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfFunctionName, + }, + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{fakeInt}, + }, + Priority: 0, + Direction: direction, + }, + }, + } + + // Objects to track in the fake client. + objs := []runtime.Object{fakeNode, tcx} + + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, tcx) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.TcxProgramList{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfProgram{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfProgramList{}) + + // Create a fake client to mock API calls. + cl := fake.NewClientBuilder().WithStatusSubresource(tcx).WithStatusSubresource(&bpfmaniov1alpha1.BpfProgram{}).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 := &TcxProgramReconciler{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: name, + Namespace: namespace, + }, + } + + // First reconcile should create the bpf program object + res, err := r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Check the BpfProgram Object was created successfully + err = rc.getBpfProgram(ctx, name, appProgramId, attachPoint, bpfProg) + require.NoError(t, err) + + require.NotEmpty(t, bpfProg) + // owningConfig Label was correctly set + require.Equal(t, bpfProg.Labels[internal.BpfProgramOwner], name) + // node Label was correctly set + require.Equal(t, bpfProg.Labels[internal.K8sHostLabel], fakeNode.Name) + // Finalizer is written + require.Equal(t, r.getFinalizer(), bpfProg.Finalizers[0]) + // Type is set + require.Equal(t, r.getRecType(), bpfProg.Spec.Type) + // Require no requeue + require.False(t, res.Requeue) + + // Update UID of bpfProgram with Fake UID since the fake API server won't + bpfProg.UID = types.UID(fakeUID) + err = cl.Update(ctx, bpfProg) + require.NoError(t, err) + + // Second reconcile should create the bpfman Load Request and update the + // BpfProgram object's 'Programs' field. + res, err = r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Require no requeue + require.False(t, res.Requeue) + uuid := string(bpfProg.UID) + + expectedLoadReq := &gobpfman.LoadRequest{ + Bytecode: &gobpfman.BytecodeLocation{ + Location: &gobpfman.BytecodeLocation_File{File: bytecodePath}, + }, + Name: bpfFunctionName, + ProgramType: *internal.Tc.Uint32(), + Metadata: map[string]string{internal.UuidMetadataKey: string(uuid), internal.ProgramNameKey: name}, + MapOwnerId: nil, + Attach: &gobpfman.AttachInfo{ + Info: &gobpfman.AttachInfo_TcAttachInfo{ + TcAttachInfo: &gobpfman.TCAttachInfo{ + Iface: fakeInt, + Priority: 0, + Direction: direction, + }, + }, + }, + } + + // Check that the bpfProgram's programs was correctly updated + err = rc.getBpfProgram(ctx, name, appProgramId, attachPoint, bpfProg) + require.NoError(t, err) + + // prog ID should already have been set + id, err := bpfmanagentinternal.GetID(bpfProg) + require.NoError(t, err) + + // Check the bpfLoadRequest was correctly built + if !cmp.Equal(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 update the bpfPrograms 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 = rc.getBpfProgram(ctx, name, appProgramId, attachPoint, bpfProg) + require.NoError(t, err) + + require.Equal(t, string(bpfmaniov1alpha1.BpfProgCondLoaded), bpfProg.Status.Conditions[0].Type) +} + +func TestTcxProgramControllerCreateMultiIntf(t *testing.T) { + var ( + name = "fakeTcProgram" + namespace = "bpfman" + bytecodePath = "/tmp/hello.o" + bpfFunctionName = "test" + direction = "ingress" + fakeNode = testutils.NewNode("fake-control-plane") + fakeInts = []string{"eth0", "eth1"} + ctx = context.TODO() + appProgramId0 = "" + attachPoint0 = fakeInts[0] + "-" + direction + appProgramId1 = "" + attachPoint1 = fakeInts[1] + "-" + direction + bpfProgEth0 = &bpfmaniov1alpha1.BpfProgram{} + bpfProgEth1 = &bpfmaniov1alpha1.BpfProgram{} + fakeUID0 = "ef71d42c-aa21-48e8-a697-82391d801a80" + fakeUID1 = "ef71d42c-aa21-48e8-a697-82391d801a81" + ) + // A TcProgram object with metadata and spec. + tcx := &bpfmaniov1alpha1.TcxProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: bpfmaniov1alpha1.TcxProgramSpec{ + BpfAppCommon: bpfmaniov1alpha1.BpfAppCommon{ + NodeSelector: metav1.LabelSelector{}, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + TcxProgramInfo: bpfmaniov1alpha1.TcxProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfFunctionName, + }, + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &fakeInts, + }, + Priority: 0, + Direction: direction, + }, + }, + } + + // Objects to track in the fake client. + objs := []runtime.Object{fakeNode, tcx} + + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, tcx) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfProgram{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfProgramList{}) + + // Create a fake client to mock API calls. + cl := fake.NewClientBuilder().WithStatusSubresource(tcx).WithStatusSubresource(&bpfmaniov1alpha1.BpfProgram{}).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 := &TcxProgramReconciler{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: name, + Namespace: namespace, + }, + } + + // First reconcile should create the first bpf program object + res, err := r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Check the first BpfProgram Object was created successfully + err = rc.getBpfProgram(ctx, name, appProgramId0, attachPoint0, bpfProgEth0) + require.NoError(t, err) + + require.NotEmpty(t, bpfProgEth0) + // owningConfig Label was correctly set + require.Equal(t, bpfProgEth0.Labels[internal.BpfProgramOwner], name) + // node Label was correctly set + require.Equal(t, bpfProgEth0.Labels[internal.K8sHostLabel], fakeNode.Name) + // Finalizer is written + require.Equal(t, r.getFinalizer(), bpfProgEth0.Finalizers[0]) + // Type is set + require.Equal(t, r.getRecType(), bpfProgEth0.Spec.Type) + // Require no requeue + require.False(t, res.Requeue) + + // Update UID of bpfProgram with Fake UID since the fake API server won't + bpfProgEth0.UID = types.UID(fakeUID0) + err = cl.Update(ctx, bpfProgEth0) + require.NoError(t, err) + + // Second reconcile should create the bpfman Load Requests for the first bpfProgram and update the prog id. + res, err = r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Require no requeue + require.False(t, res.Requeue) + + // Third reconcile should set the second bpf program object's status. + res, err = r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Fourth reconcile should create the bpfman Load Requests for the second bpfProgram. + res, err = r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Require no requeue + require.False(t, res.Requeue) + + // Require no requeue + require.False(t, res.Requeue) + + // Check the Second BpfProgram Object was created successfully + err = rc.getBpfProgram(ctx, name, appProgramId1, attachPoint1, bpfProgEth1) + require.NoError(t, err) + + require.NotEmpty(t, bpfProgEth1) + // owningConfig Label was correctly set + require.Equal(t, bpfProgEth1.Labels[internal.BpfProgramOwner], name) + // node Label was correctly set + require.Equal(t, bpfProgEth1.Labels[internal.K8sHostLabel], fakeNode.Name) + // Finalizer is written + require.Equal(t, r.getFinalizer(), bpfProgEth1.Finalizers[0]) + // Type is set + require.Equal(t, r.getRecType(), bpfProgEth1.Spec.Type) + + // Update UID of bpfProgram with Fake UID since the fake API server won't + bpfProgEth1.UID = types.UID(fakeUID1) + err = cl.Update(ctx, bpfProgEth1) + require.NoError(t, err) + + // Fifth reconcile should create the second bpfProgram. + res, err = r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Require no requeue + require.False(t, res.Requeue) + + // Sixth reconcile should update the second bpfProgram's status. + res, err = r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + uuid0 := string(bpfProgEth0.UID) + + expectedLoadReq0 := &gobpfman.LoadRequest{ + Bytecode: &gobpfman.BytecodeLocation{ + Location: &gobpfman.BytecodeLocation_File{File: bytecodePath}, + }, + Name: bpfFunctionName, + ProgramType: *internal.Tc.Uint32(), + Metadata: map[string]string{internal.UuidMetadataKey: string(uuid0), internal.ProgramNameKey: name}, + MapOwnerId: nil, + Attach: &gobpfman.AttachInfo{ + Info: &gobpfman.AttachInfo_TcAttachInfo{ + TcAttachInfo: &gobpfman.TCAttachInfo{ + Iface: fakeInts[0], + Priority: 0, + Direction: direction, + }, + }, + }, + } + + uuid1 := string(bpfProgEth1.UID) + + expectedLoadReq1 := &gobpfman.LoadRequest{ + Bytecode: &gobpfman.BytecodeLocation{ + Location: &gobpfman.BytecodeLocation_File{File: bytecodePath}, + }, + Name: bpfFunctionName, + ProgramType: *internal.Tc.Uint32(), + Metadata: map[string]string{internal.UuidMetadataKey: string(uuid1), internal.ProgramNameKey: name}, + MapOwnerId: nil, + Attach: &gobpfman.AttachInfo{ + Info: &gobpfman.AttachInfo_TcAttachInfo{ + TcAttachInfo: &gobpfman.TCAttachInfo{ + Iface: fakeInts[1], + Priority: 0, + Direction: direction, + }, + }, + }, + } + + // Check that the bpfProgram's maps was correctly updated + err = rc.getBpfProgram(ctx, name, appProgramId0, attachPoint0, bpfProgEth0) + require.NoError(t, err) + + // prog ID should already have been set + id0, err := bpfmanagentinternal.GetID(bpfProgEth0) + require.NoError(t, err) + + // Check that the bpfProgram's maps was correctly updated + err = rc.getBpfProgram(ctx, name, appProgramId1, attachPoint1, bpfProgEth1) + require.NoError(t, err) + + // prog ID should already have been set + id1, err := bpfmanagentinternal.GetID(bpfProgEth1) + require.NoError(t, err) + + // Check the bpfLoadRequest was correctly built + if !cmp.Equal(expectedLoadReq0, cli.LoadRequests[int(*id0)], protocmp.Transform()) { + t.Logf("Diff %v", cmp.Diff(expectedLoadReq0, cli.LoadRequests[int(*id0)], protocmp.Transform())) + t.Fatal("Built bpfman LoadRequest does not match expected") + } + + // Check the bpfLoadRequest was correctly built + if !cmp.Equal(expectedLoadReq1, cli.LoadRequests[int(*id1)], protocmp.Transform()) { + t.Logf("Diff %v", cmp.Diff(expectedLoadReq1, cli.LoadRequests[int(*id1)], protocmp.Transform())) + t.Fatal("Built bpfman LoadRequest does not match expected") + } + + // Check that the bpfProgram's maps was correctly updated + err = rc.getBpfProgram(ctx, name, appProgramId0, attachPoint0, bpfProgEth0) + require.NoError(t, err) + + // Check that the bpfProgram's maps was correctly updated + err = rc.getBpfProgram(ctx, name, appProgramId1, attachPoint1, bpfProgEth1) + require.NoError(t, err) + + // Third reconcile should update the bpfPrograms 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 = rc.getBpfProgram(ctx, name, appProgramId0, attachPoint0, bpfProgEth0) + require.NoError(t, err) + + require.Equal(t, string(bpfmaniov1alpha1.BpfProgCondLoaded), bpfProgEth0.Status.Conditions[0].Type) + + // Check that the bpfProgram's status was correctly updated + err = rc.getBpfProgram(ctx, name, appProgramId1, attachPoint1, bpfProgEth1) + require.NoError(t, err) + + require.Equal(t, string(bpfmaniov1alpha1.BpfProgCondLoaded), bpfProgEth1.Status.Conditions[0].Type) +} diff --git a/controllers/bpfman-operator/tcx-program.go b/controllers/bpfman-operator/tcx-program.go new file mode 100644 index 000000000..2de7d297b --- /dev/null +++ b/controllers/bpfman-operator/tcx-program.go @@ -0,0 +1,114 @@ +/* +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 bpfmanoperator + +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" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + "github.com/bpfman/bpfman-operator/internal" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +type TcxProgramReconciler struct { + ReconcilerCommon +} + +func (r *TcxProgramReconciler) getRecCommon() *ReconcilerCommon { + return &r.ReconcilerCommon +} + +func (r *TcxProgramReconciler) getFinalizer() string { + return internal.TcxProgramControllerFinalizer +} + +// SetupWithManager sets up the controller with the Manager. +func (r *TcxProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&bpfmaniov1alpha1.TcxProgram{}). + // Watch bpfPrograms which are owned by TcPrograms + Watches( + &bpfmaniov1alpha1.BpfProgram{}, + &handler.EnqueueRequestForObject{}, + builder.WithPredicates(predicate.And(statusChangedPredicate(), internal.BpfProgramTypePredicate(internal.TcxString))), + ). + Complete(r) +} + +//+kubebuilder:rbac:groups=bpfman.io,resources=tcxprograms,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=bpfman.io,resources=tcxprograms/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=bpfman.io,resources=tcxprograms/finalizers,verbs=update + +func (r *TcxProgramReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + r.Logger = log.FromContext(ctx) + + tcxProgram := &bpfmaniov1alpha1.TcxProgram{} + if err := r.Get(ctx, req.NamespacedName, tcxProgram); err != nil { + // list all TcProgram objects with + if errors.IsNotFound(err) { + bpfProgram := &bpfmaniov1alpha1.BpfProgram{} + if err := r.Get(ctx, req.NamespacedName, bpfProgram); 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 TcxProgram object from ownerRef + ownerRef := metav1.GetControllerOf(bpfProgram) + 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}, tcxProgram); err != nil { + if errors.IsNotFound(err) { + r.Logger.Info("tcxProgram from ownerRef not found stale reconcile exiting", "Name", req.NamespacedName) + } else { + r.Logger.Error(err, "failed getting TcProgram Object from ownerRef", "Name", req.NamespacedName) + } + return ctrl.Result{}, nil + } + + } else { + r.Logger.Error(err, "failed getting TcxProgram Object", "Name", req.NamespacedName) + return ctrl.Result{}, nil + } + } + + return reconcileBpfProgram(ctx, r, tcxProgram) +} + +func (r *TcxProgramReconciler) updateStatus(ctx context.Context, name string, cond bpfmaniov1alpha1.ProgramConditionType, message string) (ctrl.Result, error) { + // Sometimes we end up with a stale TcProgram due to races, do this + // get to ensure we're up to date before attempting a finalizer removal. + prog := &bpfmaniov1alpha1.TcxProgram{} + if err := r.Get(ctx, types.NamespacedName{Namespace: corev1.NamespaceAll, Name: name}, prog); err != nil { + r.Logger.V(1).Info("failed to get fresh TcxProgram object...requeuing") + return ctrl.Result{Requeue: true, RequeueAfter: retryDurationOperator}, nil + } + + return r.updateCondition(ctx, prog, &prog.Status.Conditions, cond, message) +} diff --git a/controllers/bpfman-operator/tcx-program_test.go b/controllers/bpfman-operator/tcx-program_test.go new file mode 100644 index 000000000..5623e995f --- /dev/null +++ b/controllers/bpfman-operator/tcx-program_test.go @@ -0,0 +1,161 @@ +/* +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 bpfmanoperator + +import ( + "context" + "fmt" + "testing" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + "github.com/bpfman/bpfman-operator/internal" + testutils "github.com/bpfman/bpfman-operator/internal/test-utils" + + "github.com/stretchr/testify/require" + 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" +) + +func TestTcxProgramReconcile(t *testing.T) { + var ( + name = "fakeTcProgram" + bytecodePath = "/tmp/hello.o" + bpfFunctionName = "test" + direction = "ingress" + fakeNode = testutils.NewNode("fake-control-plane") + fakeInt = "eth0" + ctx = context.TODO() + bpfProgName = fmt.Sprintf("%s-%s", name, fakeNode.Name) + ) + + // A TcxProgram object with metadata and spec. + tcx := &bpfmaniov1alpha1.TcxProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: bpfmaniov1alpha1.TcxProgramSpec{ + BpfAppCommon: bpfmaniov1alpha1.BpfAppCommon{ + NodeSelector: metav1.LabelSelector{}, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + TcxProgramInfo: bpfmaniov1alpha1.TcxProgramInfo{ + + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfFunctionName, + }, + InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ + Interfaces: &[]string{fakeInt}, + }, + Priority: 0, + Direction: direction, + }, + }, + } + + // The expected accompanying BpfProgram object + expectedBpfProg := &bpfmaniov1alpha1.BpfProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: bpfProgName, + OwnerReferences: []metav1.OwnerReference{ + { + Name: tcx.Name, + Controller: &[]bool{true}[0], + }, + }, + Labels: map[string]string{internal.BpfProgramOwner: tcx.Name, internal.K8sHostLabel: fakeNode.Name}, + Finalizers: []string{internal.TcxProgramControllerFinalizer}, + }, + Spec: bpfmaniov1alpha1.BpfProgramSpec{ + Type: "tcx", + }, + Status: bpfmaniov1alpha1.BpfProgramStatus{ + Conditions: []metav1.Condition{bpfmaniov1alpha1.BpfProgCondLoaded.Condition()}, + }, + } + + // Objects to track in the fake client. + objs := []runtime.Object{fakeNode, tcx, expectedBpfProg} + + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, tcx) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfProgram{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfProgramList{}) + + // Create a fake client to mock API calls. + cl := fake.NewClientBuilder().WithStatusSubresource(tcx).WithRuntimeObjects(objs...).Build() + + rc := ReconcilerCommon{ + Client: cl, + Scheme: s, + } + + // 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 := &TcxProgramReconciler{ReconcilerCommon: rc} + + // Mock request to simulate Reconcile() being called on an event for a + // watched resource . + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: name, + }, + } + + // First reconcile should add the finalzier to the tcProgram 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: tcx.Name, Namespace: metav1.NamespaceAll}, tcx) + require.NoError(t, err) + + // Check the bpfman-operator finalizer was successfully added + require.Contains(t, tcx.GetFinalizers(), internal.BpfmanOperatorFinalizer) + + // 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: tcx.Name, Namespace: metav1.NamespaceAll}, tcx) + require.NoError(t, err) + + require.Equal(t, tcx.Status.Conditions[0].Type, string(bpfmaniov1alpha1.ProgramReconcileSuccess)) + +} diff --git a/internal/constants.go b/internal/constants.go index d97cba9c1..2fc58f303 100644 --- a/internal/constants.go +++ b/internal/constants.go @@ -21,6 +21,7 @@ import "fmt" const ( XdpProgramInterface = "bpfman.io.xdpprogramcontroller/interface" TcProgramInterface = "bpfman.io.tcprogramcontroller/interface" + TcxProgramInterface = "bpfman.io.tcxprogramcontroller/interface" TracepointProgramTracepoint = "bpfman.io.tracepointprogramcontroller/tracepoint" KprobeProgramFunction = "bpfman.io.kprobeprogramcontroller/function" UprobeProgramTarget = "bpfman.io.uprobeprogramcontroller/target" @@ -76,6 +77,9 @@ const ( // TcProgramControllerFinalizer is the finalizer that holds an Tc BpfProgram // object from deletion until cleanup can be performed. TcProgramControllerFinalizer = "bpfman.io.tcprogramcontroller/finalizer" + // TcxProgramControllerFinalizer is the finalizer that holds an Tcx BpfProgram + // object from deletion until cleanup can be performed. + TcxProgramControllerFinalizer = "bpfman.io.tcxprogramcontroller/finalizer" // TracepointProgramControllerFinalizer is the finalizer that holds an Tracepoint // BpfProgram object from deletion until cleanup can be performed. TracepointProgramControllerFinalizer = "bpfman.io.tracepointprogramcontroller/finalizer" @@ -241,6 +245,7 @@ const UprobeString = "uprobe" const FentryString = "fentry" const FexitString = "fexit" const ApplicationString = "application" +const TcxString = "tcx" type ReconcileResult uint8 From 9af7dbf130239681d2ad0f8b9bd328c9a43ce67c Mon Sep 17 00:00:00 2001 From: Mohamed Mahmoud Date: Wed, 14 Aug 2024 06:59:05 -0400 Subject: [PATCH 3/8] Intg with bpfman tcx PR Signed-off-by: Mohamed Mahmoud --- .../bpfman.io_v1alpha1_bpfapplication.yaml | 7 +++ ...bpfman.io_v1alpha1_tcx_pass_tcprogram.yaml | 4 +- controllers/bpfman-agent/tcx-program.go | 6 +- controllers/bpfman-agent/tcx-program_test.go | 20 +++---- test/integration/tcx_test.go | 59 +++++++++++++++++++ 5 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 test/integration/tcx_test.go diff --git a/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml b/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml index 1fd6a2c87..b7e8f1bb1 100644 --- a/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml +++ b/config/samples/bpfman.io_v1alpha1_bpfapplication.yaml @@ -29,6 +29,13 @@ spec: 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 diff --git a/config/samples/bpfman.io_v1alpha1_tcx_pass_tcprogram.yaml b/config/samples/bpfman.io_v1alpha1_tcx_pass_tcprogram.yaml index b865f0d1f..b4f0ed476 100644 --- a/config/samples/bpfman.io_v1alpha1_tcx_pass_tcprogram.yaml +++ b/config/samples/bpfman.io_v1alpha1_tcx_pass_tcprogram.yaml @@ -5,7 +5,7 @@ metadata: app.kubernetes.io/name: tcxprogram name: tcx-pass-all-nodes spec: - bpffunctionname: pass + bpffunctionname: tcx_pass # Select all nodes nodeselector: {} interfaceselector: @@ -14,7 +14,7 @@ spec: direction: ingress bytecode: image: - url: quay.io/bpfman-bytecode/tc_pass:latest + url: quay.io/bpfman-bytecode/tcx_test:latest globaldata: GLOBAL_u8: - 0x01 diff --git a/controllers/bpfman-agent/tcx-program.go b/controllers/bpfman-agent/tcx-program.go index 53207f705..788db969e 100644 --- a/controllers/bpfman-agent/tcx-program.go +++ b/controllers/bpfman-agent/tcx-program.go @@ -19,7 +19,6 @@ package bpfmanagent import ( "context" "fmt" - bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" bpfmanagentinternal "github.com/bpfman/bpfman-operator/controllers/bpfman-agent/internal" "github.com/bpfman/bpfman-operator/internal" @@ -200,14 +199,13 @@ func (r *TcxProgramReconciler) getLoadRequest(bpfProgram *bpfmaniov1alpha1.BpfPr if err != nil { return nil, fmt.Errorf("failed to process bytecode selector: %v", err) } - loadRequest := gobpfman.LoadRequest{ Bytecode: bytecode, Name: r.currentTcxProgram.Spec.BpfFunctionName, ProgramType: uint32(internal.Tc), Attach: &gobpfman.AttachInfo{ - Info: &gobpfman.AttachInfo_TcAttachInfo{ - TcAttachInfo: &gobpfman.TCAttachInfo{ + Info: &gobpfman.AttachInfo_TcxAttachInfo{ + TcxAttachInfo: &gobpfman.TCXAttachInfo{ Priority: r.currentTcxProgram.Spec.Priority, Iface: bpfProgram.Annotations[internal.TcxProgramInterface], Direction: r.currentTcxProgram.Spec.Direction, diff --git a/controllers/bpfman-agent/tcx-program_test.go b/controllers/bpfman-agent/tcx-program_test.go index 4c759343a..090d640de 100644 --- a/controllers/bpfman-agent/tcx-program_test.go +++ b/controllers/bpfman-agent/tcx-program_test.go @@ -167,10 +167,10 @@ func TestTcxProgramControllerCreate(t *testing.T) { Metadata: map[string]string{internal.UuidMetadataKey: string(uuid), internal.ProgramNameKey: name}, MapOwnerId: nil, Attach: &gobpfman.AttachInfo{ - Info: &gobpfman.AttachInfo_TcAttachInfo{ - TcAttachInfo: &gobpfman.TCAttachInfo{ + Info: &gobpfman.AttachInfo_TcxAttachInfo{ + TcxAttachInfo: &gobpfman.TCXAttachInfo{ Iface: fakeInt, - Priority: 0, + Priority: tcx.Spec.Priority, Direction: direction, }, }, @@ -245,7 +245,7 @@ func TestTcxProgramControllerCreateMultiIntf(t *testing.T) { InterfaceSelector: bpfmaniov1alpha1.InterfaceSelector{ Interfaces: &fakeInts, }, - Priority: 0, + Priority: 10, Direction: direction, }, }, @@ -386,10 +386,10 @@ func TestTcxProgramControllerCreateMultiIntf(t *testing.T) { Metadata: map[string]string{internal.UuidMetadataKey: string(uuid0), internal.ProgramNameKey: name}, MapOwnerId: nil, Attach: &gobpfman.AttachInfo{ - Info: &gobpfman.AttachInfo_TcAttachInfo{ - TcAttachInfo: &gobpfman.TCAttachInfo{ + Info: &gobpfman.AttachInfo_TcxAttachInfo{ + TcxAttachInfo: &gobpfman.TCXAttachInfo{ Iface: fakeInts[0], - Priority: 0, + Priority: tcx.Spec.Priority, Direction: direction, }, }, @@ -407,10 +407,10 @@ func TestTcxProgramControllerCreateMultiIntf(t *testing.T) { Metadata: map[string]string{internal.UuidMetadataKey: string(uuid1), internal.ProgramNameKey: name}, MapOwnerId: nil, Attach: &gobpfman.AttachInfo{ - Info: &gobpfman.AttachInfo_TcAttachInfo{ - TcAttachInfo: &gobpfman.TCAttachInfo{ + Info: &gobpfman.AttachInfo_TcxAttachInfo{ + TcxAttachInfo: &gobpfman.TCXAttachInfo{ Iface: fakeInts[1], - Priority: 0, + Priority: tcx.Spec.Priority, Direction: direction, }, }, diff --git a/test/integration/tcx_test.go b/test/integration/tcx_test.go new file mode 100644 index 000000000..609dbca3b --- /dev/null +++ b/test/integration/tcx_test.go @@ -0,0 +1,59 @@ +//go:build integration_tests +// +build integration_tests + +package integration + +import ( + "bytes" + "context" + "io" + "testing" + "time" + + "github.com/kong/kubernetes-testing-framework/pkg/clusters" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + tcxGoCounterKustomize = "https://github.com/bpfman/bpfman/examples/config/default/go-tcx-counter/?timeout=120&ref=main" + tcxGoCounterUserspaceNs = "go-tcx-counter" + tcxGoCounterUserspaceDsName = "go-tcx-counter-ds" +) + +func TestTcxGoCounter(t *testing.T) { + t.Log("deploying tcx counter program") + require.NoError(t, clusters.KustomizeDeployForCluster(ctx, env.Cluster(), tcxGoCounterKustomize)) + addCleanup(func(context.Context) error { + cleanupLog("cleaning up tcx counter program") + return clusters.KustomizeDeleteForCluster(ctx, env.Cluster(), tcxGoCounterKustomize) + }) + + t.Log("waiting for go tcx counter userspace daemon to be available") + require.Eventually(t, func() bool { + daemon, err := env.Cluster().Client().AppsV1().DaemonSets(tcxGoCounterUserspaceNs).Get(ctx, tcxGoCounterUserspaceDsName, metav1.GetOptions{}) + require.NoError(t, err) + return daemon.Status.DesiredNumberScheduled == daemon.Status.NumberAvailable + }, + // Wait 5 minutes since cosign is slow, https://github.com/bpfman/bpfman/issues/1043 + 5*time.Minute, 10*time.Second) + + pods, err := env.Cluster().Client().CoreV1().Pods(tcxGoCounterUserspaceNs).List(ctx, metav1.ListOptions{LabelSelector: "name=go-tcx-counter"}) + require.NoError(t, err) + gotcCounterPod := pods.Items[0] + + req := env.Cluster().Client().CoreV1().Pods(tcxGoCounterUserspaceNs).GetLogs(gotcCounterPod.Name, &corev1.PodLogOptions{}) + + require.Eventually(t, func() bool { + logs, err := req.Stream(ctx) + require.NoError(t, err) + defer logs.Close() + output := new(bytes.Buffer) + _, err = io.Copy(output, logs) + require.NoError(t, err) + t.Logf("counter pod log %s", output.String()) + + return doTcCheck(t, output) + }, 30*time.Second, time.Second) +} From 4ad964d7c78c29cbb35f31a02ccfa7f6d5017c74 Mon Sep 17 00:00:00 2001 From: Mohamed Mahmoud Date: Tue, 8 Oct 2024 16:34:10 -0400 Subject: [PATCH 4/8] Add TCX example to bundle csv Signed-off-by: Mohamed Mahmoud --- .../bpfman-operator.clusterserviceversion.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bundle/manifests/bpfman-operator.clusterserviceversion.yaml b/bundle/manifests/bpfman-operator.clusterserviceversion.yaml index 1629a2300..59339fa32 100644 --- a/bundle/manifests/bpfman-operator.clusterserviceversion.yaml +++ b/bundle/manifests/bpfman-operator.clusterserviceversion.yaml @@ -50,6 +50,17 @@ metadata: }, "type": "TC" }, + { + "tcx": { + "bpffunctionname": "tcx_stats", + "direction": "ingress", + "interfaceselector": { + "primarynodeinterface": true + }, + "priority": 500 + }, + "type": "TCX" + }, { "type": "Uprobe", "uprobe": { From c96f81680e0237e677251e15d4791616db9d8736 Mon Sep 17 00:00:00 2001 From: Mohamed Mahmoud Date: Mon, 21 Oct 2024 17:39:40 -0400 Subject: [PATCH 5/8] update bpfman dependency to pick TCX support Signed-off-by: Mohamed Mahmoud --- go.mod | 2 +- go.sum | 4 +- .../bpfman/clients/gobpfman/v1/bpfman.pb.go | 738 ++++++++++-------- vendor/modules.txt | 2 +- 4 files changed, 429 insertions(+), 317 deletions(-) diff --git a/go.mod b/go.mod index 1f65c367d..47afed458 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.0 toolchain go1.22.2 require ( - github.com/bpfman/bpfman v0.5.4 + github.com/bpfman/bpfman v0.5.5-0.20241022174147-497c1ed71c81 github.com/containers/image/v5 v5.32.2 github.com/go-logr/logr v1.4.2 github.com/google/go-cmp v0.6.0 diff --git a/go.sum b/go.sum index a0de1b56d..deb7b408e 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/bpfman/bpfman v0.5.4 h1:pfdCNmEY8uGsfOiBAtwm4pWj+OU8Nqi896U49aONlcE= -github.com/bpfman/bpfman v0.5.4/go.mod h1:ZBZc5wo+lEQA+w/89Sbjaw5VhuvuLTDS3a3yDjOl81o= +github.com/bpfman/bpfman v0.5.5-0.20241022174147-497c1ed71c81 h1:cDjf1+aZhWsLc9FsJ7Li/R4NHvm4pUPIfXU+6AL90aQ= +github.com/bpfman/bpfman v0.5.5-0.20241022174147-497c1ed71c81/go.mod h1:ZBZc5wo+lEQA+w/89Sbjaw5VhuvuLTDS3a3yDjOl81o= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= diff --git a/vendor/github.com/bpfman/bpfman/clients/gobpfman/v1/bpfman.pb.go b/vendor/github.com/bpfman/bpfman/clients/gobpfman/v1/bpfman.pb.go index 520ae2081..d61732ae4 100644 --- a/vendor/github.com/bpfman/bpfman/clients/gobpfman/v1/bpfman.pb.go +++ b/vendor/github.com/bpfman/bpfman/clients/gobpfman/v1/bpfman.pb.go @@ -573,6 +573,77 @@ func (x *TCAttachInfo) GetProceedOn() []int32 { return nil } +type TCXAttachInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Priority int32 `protobuf:"varint,1,opt,name=priority,proto3" json:"priority,omitempty"` + Iface string `protobuf:"bytes,2,opt,name=iface,proto3" json:"iface,omitempty"` + Position int32 `protobuf:"varint,3,opt,name=position,proto3" json:"position,omitempty"` + Direction string `protobuf:"bytes,4,opt,name=direction,proto3" json:"direction,omitempty"` +} + +func (x *TCXAttachInfo) Reset() { + *x = TCXAttachInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_bpfman_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TCXAttachInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TCXAttachInfo) ProtoMessage() {} + +func (x *TCXAttachInfo) ProtoReflect() protoreflect.Message { + mi := &file_bpfman_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TCXAttachInfo.ProtoReflect.Descriptor instead. +func (*TCXAttachInfo) Descriptor() ([]byte, []int) { + return file_bpfman_proto_rawDescGZIP(), []int{6} +} + +func (x *TCXAttachInfo) GetPriority() int32 { + if x != nil { + return x.Priority + } + return 0 +} + +func (x *TCXAttachInfo) GetIface() string { + if x != nil { + return x.Iface + } + return "" +} + +func (x *TCXAttachInfo) GetPosition() int32 { + if x != nil { + return x.Position + } + return 0 +} + +func (x *TCXAttachInfo) GetDirection() string { + if x != nil { + return x.Direction + } + return "" +} + type TracepointAttachInfo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -584,7 +655,7 @@ type TracepointAttachInfo struct { func (x *TracepointAttachInfo) Reset() { *x = TracepointAttachInfo{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[6] + mi := &file_bpfman_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -597,7 +668,7 @@ func (x *TracepointAttachInfo) String() string { func (*TracepointAttachInfo) ProtoMessage() {} func (x *TracepointAttachInfo) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[6] + mi := &file_bpfman_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -610,7 +681,7 @@ func (x *TracepointAttachInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use TracepointAttachInfo.ProtoReflect.Descriptor instead. func (*TracepointAttachInfo) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{6} + return file_bpfman_proto_rawDescGZIP(), []int{7} } func (x *TracepointAttachInfo) GetTracepoint() string { @@ -634,7 +705,7 @@ type KprobeAttachInfo struct { func (x *KprobeAttachInfo) Reset() { *x = KprobeAttachInfo{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[7] + mi := &file_bpfman_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -647,7 +718,7 @@ func (x *KprobeAttachInfo) String() string { func (*KprobeAttachInfo) ProtoMessage() {} func (x *KprobeAttachInfo) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[7] + mi := &file_bpfman_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -660,7 +731,7 @@ func (x *KprobeAttachInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use KprobeAttachInfo.ProtoReflect.Descriptor instead. func (*KprobeAttachInfo) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{7} + return file_bpfman_proto_rawDescGZIP(), []int{8} } func (x *KprobeAttachInfo) GetFnName() string { @@ -707,7 +778,7 @@ type UprobeAttachInfo struct { func (x *UprobeAttachInfo) Reset() { *x = UprobeAttachInfo{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[8] + mi := &file_bpfman_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -720,7 +791,7 @@ func (x *UprobeAttachInfo) String() string { func (*UprobeAttachInfo) ProtoMessage() {} func (x *UprobeAttachInfo) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[8] + mi := &file_bpfman_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -733,7 +804,7 @@ func (x *UprobeAttachInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use UprobeAttachInfo.ProtoReflect.Descriptor instead. func (*UprobeAttachInfo) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{8} + return file_bpfman_proto_rawDescGZIP(), []int{9} } func (x *UprobeAttachInfo) GetFnName() string { @@ -789,7 +860,7 @@ type FentryAttachInfo struct { func (x *FentryAttachInfo) Reset() { *x = FentryAttachInfo{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[9] + mi := &file_bpfman_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -802,7 +873,7 @@ func (x *FentryAttachInfo) String() string { func (*FentryAttachInfo) ProtoMessage() {} func (x *FentryAttachInfo) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[9] + mi := &file_bpfman_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -815,7 +886,7 @@ func (x *FentryAttachInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use FentryAttachInfo.ProtoReflect.Descriptor instead. func (*FentryAttachInfo) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{9} + return file_bpfman_proto_rawDescGZIP(), []int{10} } func (x *FentryAttachInfo) GetFnName() string { @@ -836,7 +907,7 @@ type FexitAttachInfo struct { func (x *FexitAttachInfo) Reset() { *x = FexitAttachInfo{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[10] + mi := &file_bpfman_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -849,7 +920,7 @@ func (x *FexitAttachInfo) String() string { func (*FexitAttachInfo) ProtoMessage() {} func (x *FexitAttachInfo) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[10] + mi := &file_bpfman_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -862,7 +933,7 @@ func (x *FexitAttachInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use FexitAttachInfo.ProtoReflect.Descriptor instead. func (*FexitAttachInfo) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{10} + return file_bpfman_proto_rawDescGZIP(), []int{11} } func (x *FexitAttachInfo) GetFnName() string { @@ -886,13 +957,14 @@ type AttachInfo struct { // *AttachInfo_UprobeAttachInfo // *AttachInfo_FentryAttachInfo // *AttachInfo_FexitAttachInfo + // *AttachInfo_TcxAttachInfo Info isAttachInfo_Info `protobuf_oneof:"info"` } func (x *AttachInfo) Reset() { *x = AttachInfo{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[11] + mi := &file_bpfman_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -905,7 +977,7 @@ func (x *AttachInfo) String() string { func (*AttachInfo) ProtoMessage() {} func (x *AttachInfo) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[11] + mi := &file_bpfman_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -918,7 +990,7 @@ func (x *AttachInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachInfo.ProtoReflect.Descriptor instead. func (*AttachInfo) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{11} + return file_bpfman_proto_rawDescGZIP(), []int{12} } func (m *AttachInfo) GetInfo() isAttachInfo_Info { @@ -977,6 +1049,13 @@ func (x *AttachInfo) GetFexitAttachInfo() *FexitAttachInfo { return nil } +func (x *AttachInfo) GetTcxAttachInfo() *TCXAttachInfo { + if x, ok := x.GetInfo().(*AttachInfo_TcxAttachInfo); ok { + return x.TcxAttachInfo + } + return nil +} + type isAttachInfo_Info interface { isAttachInfo_Info() } @@ -1009,6 +1088,10 @@ type AttachInfo_FexitAttachInfo struct { FexitAttachInfo *FexitAttachInfo `protobuf:"bytes,8,opt,name=fexit_attach_info,json=fexitAttachInfo,proto3,oneof"` } +type AttachInfo_TcxAttachInfo struct { + TcxAttachInfo *TCXAttachInfo `protobuf:"bytes,9,opt,name=tcx_attach_info,json=tcxAttachInfo,proto3,oneof"` +} + func (*AttachInfo_XdpAttachInfo) isAttachInfo_Info() {} func (*AttachInfo_TcAttachInfo) isAttachInfo_Info() {} @@ -1023,6 +1106,8 @@ func (*AttachInfo_FentryAttachInfo) isAttachInfo_Info() {} func (*AttachInfo_FexitAttachInfo) isAttachInfo_Info() {} +func (*AttachInfo_TcxAttachInfo) isAttachInfo_Info() {} + type LoadRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1041,7 +1126,7 @@ type LoadRequest struct { func (x *LoadRequest) Reset() { *x = LoadRequest{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[12] + mi := &file_bpfman_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1054,7 +1139,7 @@ func (x *LoadRequest) String() string { func (*LoadRequest) ProtoMessage() {} func (x *LoadRequest) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[12] + mi := &file_bpfman_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1067,7 +1152,7 @@ func (x *LoadRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LoadRequest.ProtoReflect.Descriptor instead. func (*LoadRequest) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{12} + return file_bpfman_proto_rawDescGZIP(), []int{13} } func (x *LoadRequest) GetBytecode() *BytecodeLocation { @@ -1138,7 +1223,7 @@ type LoadResponse struct { func (x *LoadResponse) Reset() { *x = LoadResponse{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[13] + mi := &file_bpfman_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1151,7 +1236,7 @@ func (x *LoadResponse) String() string { func (*LoadResponse) ProtoMessage() {} func (x *LoadResponse) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[13] + mi := &file_bpfman_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1164,7 +1249,7 @@ func (x *LoadResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LoadResponse.ProtoReflect.Descriptor instead. func (*LoadResponse) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{13} + return file_bpfman_proto_rawDescGZIP(), []int{14} } func (x *LoadResponse) GetInfo() *ProgramInfo { @@ -1192,7 +1277,7 @@ type UnloadRequest struct { func (x *UnloadRequest) Reset() { *x = UnloadRequest{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[14] + mi := &file_bpfman_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1205,7 +1290,7 @@ func (x *UnloadRequest) String() string { func (*UnloadRequest) ProtoMessage() {} func (x *UnloadRequest) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[14] + mi := &file_bpfman_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1218,7 +1303,7 @@ func (x *UnloadRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UnloadRequest.ProtoReflect.Descriptor instead. func (*UnloadRequest) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{14} + return file_bpfman_proto_rawDescGZIP(), []int{15} } func (x *UnloadRequest) GetId() uint32 { @@ -1237,7 +1322,7 @@ type UnloadResponse struct { func (x *UnloadResponse) Reset() { *x = UnloadResponse{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[15] + mi := &file_bpfman_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1250,7 +1335,7 @@ func (x *UnloadResponse) String() string { func (*UnloadResponse) ProtoMessage() {} func (x *UnloadResponse) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[15] + mi := &file_bpfman_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1263,7 +1348,7 @@ func (x *UnloadResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UnloadResponse.ProtoReflect.Descriptor instead. func (*UnloadResponse) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{15} + return file_bpfman_proto_rawDescGZIP(), []int{16} } type ListRequest struct { @@ -1279,7 +1364,7 @@ type ListRequest struct { func (x *ListRequest) Reset() { *x = ListRequest{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[16] + mi := &file_bpfman_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1292,7 +1377,7 @@ func (x *ListRequest) String() string { func (*ListRequest) ProtoMessage() {} func (x *ListRequest) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[16] + mi := &file_bpfman_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1305,7 +1390,7 @@ func (x *ListRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRequest.ProtoReflect.Descriptor instead. func (*ListRequest) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{16} + return file_bpfman_proto_rawDescGZIP(), []int{17} } func (x *ListRequest) GetProgramType() uint32 { @@ -1340,7 +1425,7 @@ type ListResponse struct { func (x *ListResponse) Reset() { *x = ListResponse{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[17] + mi := &file_bpfman_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1353,7 +1438,7 @@ func (x *ListResponse) String() string { func (*ListResponse) ProtoMessage() {} func (x *ListResponse) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[17] + mi := &file_bpfman_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1366,7 +1451,7 @@ func (x *ListResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListResponse.ProtoReflect.Descriptor instead. func (*ListResponse) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{17} + return file_bpfman_proto_rawDescGZIP(), []int{18} } func (x *ListResponse) GetResults() []*ListResponse_ListResult { @@ -1387,7 +1472,7 @@ type PullBytecodeRequest struct { func (x *PullBytecodeRequest) Reset() { *x = PullBytecodeRequest{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[18] + mi := &file_bpfman_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1400,7 +1485,7 @@ func (x *PullBytecodeRequest) String() string { func (*PullBytecodeRequest) ProtoMessage() {} func (x *PullBytecodeRequest) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[18] + mi := &file_bpfman_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1413,7 +1498,7 @@ func (x *PullBytecodeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PullBytecodeRequest.ProtoReflect.Descriptor instead. func (*PullBytecodeRequest) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{18} + return file_bpfman_proto_rawDescGZIP(), []int{19} } func (x *PullBytecodeRequest) GetImage() *BytecodeImage { @@ -1432,7 +1517,7 @@ type PullBytecodeResponse struct { func (x *PullBytecodeResponse) Reset() { *x = PullBytecodeResponse{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[19] + mi := &file_bpfman_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1445,7 +1530,7 @@ func (x *PullBytecodeResponse) String() string { func (*PullBytecodeResponse) ProtoMessage() {} func (x *PullBytecodeResponse) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[19] + mi := &file_bpfman_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1458,7 +1543,7 @@ func (x *PullBytecodeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PullBytecodeResponse.ProtoReflect.Descriptor instead. func (*PullBytecodeResponse) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{19} + return file_bpfman_proto_rawDescGZIP(), []int{20} } type GetRequest struct { @@ -1472,7 +1557,7 @@ type GetRequest struct { func (x *GetRequest) Reset() { *x = GetRequest{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[20] + mi := &file_bpfman_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1485,7 +1570,7 @@ func (x *GetRequest) String() string { func (*GetRequest) ProtoMessage() {} func (x *GetRequest) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[20] + mi := &file_bpfman_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1498,7 +1583,7 @@ func (x *GetRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRequest.ProtoReflect.Descriptor instead. func (*GetRequest) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{20} + return file_bpfman_proto_rawDescGZIP(), []int{21} } func (x *GetRequest) GetId() uint32 { @@ -1520,7 +1605,7 @@ type GetResponse struct { func (x *GetResponse) Reset() { *x = GetResponse{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[21] + mi := &file_bpfman_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1533,7 +1618,7 @@ func (x *GetResponse) String() string { func (*GetResponse) ProtoMessage() {} func (x *GetResponse) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[21] + mi := &file_bpfman_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1546,7 +1631,7 @@ func (x *GetResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetResponse.ProtoReflect.Descriptor instead. func (*GetResponse) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{21} + return file_bpfman_proto_rawDescGZIP(), []int{22} } func (x *GetResponse) GetInfo() *ProgramInfo { @@ -1575,7 +1660,7 @@ type ListResponse_ListResult struct { func (x *ListResponse_ListResult) Reset() { *x = ListResponse_ListResult{} if protoimpl.UnsafeEnabled { - mi := &file_bpfman_proto_msgTypes[27] + mi := &file_bpfman_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1588,7 +1673,7 @@ func (x *ListResponse_ListResult) String() string { func (*ListResponse_ListResult) ProtoMessage() {} func (x *ListResponse_ListResult) ProtoReflect() protoreflect.Message { - mi := &file_bpfman_proto_msgTypes[27] + mi := &file_bpfman_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1601,7 +1686,7 @@ func (x *ListResponse_ListResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ListResponse_ListResult.ProtoReflect.Descriptor instead. func (*ListResponse_ListResult) Descriptor() ([]byte, []int) { - return file_bpfman_proto_rawDescGZIP(), []int{17, 0} + return file_bpfman_proto_rawDescGZIP(), []int{18, 0} } func (x *ListResponse_ListResult) GetInfo() *ProgramInfo { @@ -1714,191 +1799,203 @@ var file_bpfman_proto_rawDesc = []byte{ 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x65, 0x64, 0x5f, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x03, - 0x28, 0x05, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x65, 0x64, 0x4f, 0x6e, 0x22, 0x36, 0x0a, - 0x14, 0x54, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, - 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x72, 0x61, 0x63, 0x65, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x9b, 0x01, 0x0a, 0x10, 0x4b, 0x70, 0x72, 0x6f, 0x62, 0x65, + 0x28, 0x05, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x65, 0x64, 0x4f, 0x6e, 0x22, 0x7b, 0x0a, + 0x0d, 0x54, 0x43, 0x58, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x66, + 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x66, 0x61, 0x63, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x36, 0x0a, 0x14, 0x54, 0x72, + 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x22, 0x9b, 0x01, 0x0a, 0x10, 0x4b, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x41, 0x74, 0x74, + 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6e, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6e, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x74, 0x70, + 0x72, 0x6f, 0x62, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x74, 0x70, + 0x72, 0x6f, 0x62, 0x65, 0x12, 0x28, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x0c, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x69, 0x64, 0x88, 0x01, 0x01, 0x42, 0x10, + 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x69, 0x64, + 0x22, 0xe3, 0x01, 0x0a, 0x10, 0x55, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x41, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x07, 0x66, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x66, 0x6e, 0x4e, 0x61, 0x6d, 0x65, + 0x88, 0x01, 0x01, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x74, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x74, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x12, + 0x15, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x03, + 0x70, 0x69, 0x64, 0x88, 0x01, 0x01, 0x12, 0x28, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x48, 0x02, 0x52, + 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x69, 0x64, 0x88, 0x01, 0x01, + 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x66, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x06, 0x0a, 0x04, + 0x5f, 0x70, 0x69, 0x64, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x5f, 0x70, 0x69, 0x64, 0x22, 0x2b, 0x0a, 0x10, 0x46, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6e, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, - 0x65, 0x74, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, - 0x65, 0x74, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x12, 0x28, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, - 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x69, 0x64, 0x88, 0x01, - 0x01, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, - 0x70, 0x69, 0x64, 0x22, 0xe3, 0x01, 0x0a, 0x10, 0x55, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x41, 0x74, - 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x07, 0x66, 0x6e, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x66, 0x6e, 0x4e, - 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x16, - 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x74, 0x70, 0x72, 0x6f, - 0x62, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x74, 0x70, 0x72, 0x6f, - 0x62, 0x65, 0x12, 0x15, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x48, - 0x01, 0x52, 0x03, 0x70, 0x69, 0x64, 0x88, 0x01, 0x01, 0x12, 0x28, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, - 0x48, 0x02, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x69, 0x64, - 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x66, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, - 0x06, 0x0a, 0x04, 0x5f, 0x70, 0x69, 0x64, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x69, 0x64, 0x22, 0x2b, 0x0a, 0x10, 0x46, 0x65, 0x6e, - 0x74, 0x72, 0x79, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x17, 0x0a, - 0x07, 0x66, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x66, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x2a, 0x0a, 0x0f, 0x46, 0x65, 0x78, 0x69, 0x74, 0x41, - 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6e, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6e, 0x4e, 0x61, - 0x6d, 0x65, 0x22, 0xa3, 0x04, 0x0a, 0x0a, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, - 0x6f, 0x12, 0x42, 0x0a, 0x0f, 0x78, 0x64, 0x70, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5f, - 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x70, 0x66, - 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x58, 0x44, 0x50, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, - 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x0d, 0x78, 0x64, 0x70, 0x41, 0x74, 0x74, 0x61, 0x63, - 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3f, 0x0a, 0x0e, 0x74, 0x63, 0x5f, 0x61, 0x74, 0x74, 0x61, - 0x63, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x43, 0x41, 0x74, 0x74, 0x61, - 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x0c, 0x74, 0x63, 0x41, 0x74, 0x74, 0x61, - 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x57, 0x0a, 0x16, 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x74, 0x74, - 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x14, 0x74, 0x72, 0x61, 0x63, 0x65, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x4b, 0x0a, 0x12, 0x6b, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, - 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x70, - 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x41, 0x74, - 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x10, 0x6b, 0x70, 0x72, 0x6f, - 0x62, 0x65, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4b, 0x0a, 0x12, - 0x75, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5f, 0x69, 0x6e, - 0x66, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, - 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x41, 0x74, 0x74, 0x61, 0x63, - 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x10, 0x75, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x41, - 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4b, 0x0a, 0x12, 0x66, 0x65, 0x6e, - 0x74, 0x72, 0x79, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x46, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, - 0x66, 0x6f, 0x48, 0x00, 0x52, 0x10, 0x66, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x41, 0x74, 0x74, 0x61, - 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x48, 0x0a, 0x11, 0x66, 0x65, 0x78, 0x69, 0x74, 0x5f, - 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, - 0x78, 0x69, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, - 0x0f, 0x66, 0x65, 0x78, 0x69, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, - 0x42, 0x06, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x8d, 0x04, 0x0a, 0x0b, 0x4c, 0x6f, 0x61, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x37, 0x0a, 0x08, 0x62, 0x79, 0x74, 0x65, - 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x70, 0x66, - 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x62, 0x79, 0x74, 0x65, 0x63, 0x6f, 0x64, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, - 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x72, 0x6f, - 0x67, 0x72, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x61, 0x74, 0x74, 0x61, - 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, - 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x06, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x12, 0x40, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x62, 0x70, 0x66, 0x6d, - 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x47, 0x0a, 0x0b, 0x67, 0x6c, 0x6f, - 0x62, 0x61, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, - 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x44, 0x61, 0x74, - 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x44, 0x61, - 0x74, 0x61, 0x12, 0x17, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x48, 0x00, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0c, 0x6d, - 0x61, 0x70, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x0d, 0x48, 0x01, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x88, - 0x01, 0x01, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, + 0x61, 0x6d, 0x65, 0x22, 0x2a, 0x0a, 0x0f, 0x46, 0x65, 0x78, 0x69, 0x74, 0x41, 0x74, 0x74, 0x61, + 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x22, + 0xe7, 0x04, 0x0a, 0x0a, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x42, + 0x0a, 0x0f, 0x78, 0x64, 0x70, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5f, 0x69, 0x6e, 0x66, + 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, + 0x2e, 0x76, 0x31, 0x2e, 0x58, 0x44, 0x50, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, + 0x6f, 0x48, 0x00, 0x52, 0x0d, 0x78, 0x64, 0x70, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x3f, 0x0a, 0x0e, 0x74, 0x63, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5f, + 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x70, 0x66, + 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x43, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, + 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x0c, 0x74, 0x63, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x57, 0x0a, 0x16, 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, + 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x14, 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4b, 0x0a, 0x12, + 0x6b, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5f, 0x69, 0x6e, + 0x66, 0x6f, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, + 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x41, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x10, 0x6b, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x41, + 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4b, 0x0a, 0x12, 0x75, 0x70, 0x72, + 0x6f, 0x62, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, + 0x31, 0x2e, 0x55, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, + 0x66, 0x6f, 0x48, 0x00, 0x52, 0x10, 0x75, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x41, 0x74, 0x74, 0x61, + 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4b, 0x0a, 0x12, 0x66, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x46, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x48, + 0x00, 0x52, 0x10, 0x66, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x48, 0x0a, 0x11, 0x66, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x61, 0x74, 0x74, + 0x61, 0x63, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x65, 0x78, 0x69, 0x74, + 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x0f, 0x66, 0x65, + 0x78, 0x69, 0x74, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x42, 0x0a, + 0x0f, 0x74, 0x63, 0x78, 0x5f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x54, 0x43, 0x58, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, + 0x48, 0x00, 0x52, 0x0d, 0x74, 0x63, 0x78, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, + 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x8d, 0x04, 0x0a, 0x0b, 0x4c, 0x6f, + 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x37, 0x0a, 0x08, 0x62, 0x79, 0x74, + 0x65, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x70, + 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x63, 0x6f, 0x64, 0x65, + 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x62, 0x79, 0x74, 0x65, 0x63, 0x6f, + 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, + 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x72, + 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x61, 0x74, 0x74, + 0x61, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x62, 0x70, 0x66, 0x6d, + 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x06, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x12, 0x40, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x62, 0x70, 0x66, + 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x47, 0x0a, 0x0b, 0x67, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x26, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x61, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x44, 0x61, + 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x44, + 0x61, 0x74, 0x61, 0x12, 0x17, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0c, + 0x6d, 0x61, 0x70, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0d, 0x48, 0x01, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, + 0x88, 0x01, 0x01, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x1a, 0x3d, 0x0a, 0x0f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, - 0x3d, 0x0a, 0x0f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x07, - 0x0a, 0x05, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x6d, 0x61, 0x70, 0x5f, - 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x22, 0x79, 0x0a, 0x0c, 0x4c, 0x6f, 0x61, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, + 0x07, 0x0a, 0x05, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x6d, 0x61, 0x70, + 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x22, 0x79, 0x0a, 0x0c, 0x4c, 0x6f, 0x61, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x04, 0x69, 0x6e, 0x66, + 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x0b, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x5f, + 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x70, 0x66, + 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, + 0x67, 0x72, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, + 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x1f, 0x0a, 0x0d, 0x55, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x02, 0x69, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x55, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xaa, 0x02, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x67, 0x72, + 0x61, 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, + 0x0b, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, + 0x35, 0x0a, 0x14, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, + 0x6d, 0x73, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, + 0x12, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x73, 0x4f, + 0x6e, 0x6c, 0x79, 0x88, 0x01, 0x01, 0x12, 0x50, 0x0a, 0x0e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, + 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x40, 0x0a, 0x12, 0x4d, 0x61, 0x74, 0x63, + 0x68, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x70, + 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x17, 0x0a, 0x15, 0x5f, + 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x73, 0x5f, + 0x6f, 0x6e, 0x6c, 0x79, 0x22, 0xd4, 0x01, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x73, 0x1a, 0x85, 0x01, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, + 0x67, 0x72, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, + 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x0b, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, + 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, + 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x67, 0x72, + 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x49, 0x6e, + 0x66, 0x6f, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x45, 0x0a, 0x13, 0x50, + 0x75, 0x6c, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x79, + 0x74, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6d, 0x61, + 0x67, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x50, 0x75, 0x6c, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x63, 0x6f, + 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x0a, 0x0a, 0x47, 0x65, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x22, 0x86, 0x01, 0x0a, 0x0b, 0x47, 0x65, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, - 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x0b, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x5f, 0x69, - 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x70, 0x66, 0x6d, - 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x67, - 0x72, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x49, - 0x6e, 0x66, 0x6f, 0x22, 0x1f, 0x0a, 0x0d, 0x55, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x02, 0x69, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x55, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xaa, 0x02, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, - 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x0b, - 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x35, - 0x0a, 0x14, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, - 0x73, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x12, - 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x73, 0x4f, 0x6e, - 0x6c, 0x79, 0x88, 0x01, 0x01, 0x12, 0x50, 0x0a, 0x0e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, - 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x40, 0x0a, 0x12, 0x4d, 0x61, 0x74, 0x63, 0x68, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x70, 0x72, - 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x62, - 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x73, 0x5f, 0x6f, - 0x6e, 0x6c, 0x79, 0x22, 0xd4, 0x01, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x73, 0x1a, 0x85, 0x01, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x67, - 0x72, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x88, - 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x0b, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x66, - 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, - 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, - 0x6f, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x45, 0x0a, 0x13, 0x50, 0x75, - 0x6c, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x2e, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x18, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x79, 0x74, - 0x65, 0x63, 0x6f, 0x64, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, - 0x65, 0x22, 0x16, 0x0a, 0x14, 0x50, 0x75, 0x6c, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x63, 0x6f, 0x64, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x0a, 0x0a, 0x47, 0x65, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x22, 0x86, 0x01, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, - 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x0b, 0x6b, 0x65, 0x72, 0x6e, - 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, - 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, - 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x6b, 0x65, 0x72, - 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x69, 0x6e, 0x66, 0x6f, - 0x32, 0xc0, 0x02, 0x0a, 0x06, 0x42, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x12, 0x37, 0x0a, 0x04, 0x4c, - 0x6f, 0x61, 0x64, 0x12, 0x16, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x62, 0x70, - 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x55, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x18, - 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x6c, 0x6f, 0x61, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, - 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x62, 0x70, - 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x0c, - 0x50, 0x75, 0x6c, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x2e, 0x62, - 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x6c, 0x6c, 0x42, 0x79, 0x74, - 0x65, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x62, - 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x6c, 0x6c, 0x42, 0x79, 0x74, - 0x65, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, - 0x03, 0x47, 0x65, 0x74, 0x12, 0x15, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x62, 0x70, - 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, - 0x2f, 0x67, 0x6f, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, + 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x0b, 0x6b, 0x65, 0x72, + 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x65, 0x72, 0x6e, 0x65, + 0x6c, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x6b, 0x65, + 0x72, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x69, 0x6e, 0x66, + 0x6f, 0x32, 0xc0, 0x02, 0x0a, 0x06, 0x42, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x12, 0x37, 0x0a, 0x04, + 0x4c, 0x6f, 0x61, 0x64, 0x12, 0x16, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, + 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x62, + 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x55, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, + 0x18, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x6c, 0x6f, + 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x62, 0x70, 0x66, 0x6d, + 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x62, + 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, + 0x0c, 0x50, 0x75, 0x6c, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x2e, + 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x6c, 0x6c, 0x42, 0x79, + 0x74, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, + 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x6c, 0x6c, 0x42, 0x79, + 0x74, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, + 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x15, 0x2e, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x62, + 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x73, 0x2f, 0x67, 0x6f, 0x62, 0x70, 0x66, 0x6d, 0x61, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1913,7 +2010,7 @@ func file_bpfman_proto_rawDescGZIP() []byte { return file_bpfman_proto_rawDescData } -var file_bpfman_proto_msgTypes = make([]protoimpl.MessageInfo, 28) +var file_bpfman_proto_msgTypes = make([]protoimpl.MessageInfo, 29) var file_bpfman_proto_goTypes = []interface{}{ (*BytecodeImage)(nil), // 0: bpfman.v1.BytecodeImage (*BytecodeLocation)(nil), // 1: bpfman.v1.BytecodeLocation @@ -1921,70 +2018,72 @@ var file_bpfman_proto_goTypes = []interface{}{ (*ProgramInfo)(nil), // 3: bpfman.v1.ProgramInfo (*XDPAttachInfo)(nil), // 4: bpfman.v1.XDPAttachInfo (*TCAttachInfo)(nil), // 5: bpfman.v1.TCAttachInfo - (*TracepointAttachInfo)(nil), // 6: bpfman.v1.TracepointAttachInfo - (*KprobeAttachInfo)(nil), // 7: bpfman.v1.KprobeAttachInfo - (*UprobeAttachInfo)(nil), // 8: bpfman.v1.UprobeAttachInfo - (*FentryAttachInfo)(nil), // 9: bpfman.v1.FentryAttachInfo - (*FexitAttachInfo)(nil), // 10: bpfman.v1.FexitAttachInfo - (*AttachInfo)(nil), // 11: bpfman.v1.AttachInfo - (*LoadRequest)(nil), // 12: bpfman.v1.LoadRequest - (*LoadResponse)(nil), // 13: bpfman.v1.LoadResponse - (*UnloadRequest)(nil), // 14: bpfman.v1.UnloadRequest - (*UnloadResponse)(nil), // 15: bpfman.v1.UnloadResponse - (*ListRequest)(nil), // 16: bpfman.v1.ListRequest - (*ListResponse)(nil), // 17: bpfman.v1.ListResponse - (*PullBytecodeRequest)(nil), // 18: bpfman.v1.PullBytecodeRequest - (*PullBytecodeResponse)(nil), // 19: bpfman.v1.PullBytecodeResponse - (*GetRequest)(nil), // 20: bpfman.v1.GetRequest - (*GetResponse)(nil), // 21: bpfman.v1.GetResponse - nil, // 22: bpfman.v1.ProgramInfo.GlobalDataEntry - nil, // 23: bpfman.v1.ProgramInfo.MetadataEntry - nil, // 24: bpfman.v1.LoadRequest.MetadataEntry - nil, // 25: bpfman.v1.LoadRequest.GlobalDataEntry - nil, // 26: bpfman.v1.ListRequest.MatchMetadataEntry - (*ListResponse_ListResult)(nil), // 27: bpfman.v1.ListResponse.ListResult + (*TCXAttachInfo)(nil), // 6: bpfman.v1.TCXAttachInfo + (*TracepointAttachInfo)(nil), // 7: bpfman.v1.TracepointAttachInfo + (*KprobeAttachInfo)(nil), // 8: bpfman.v1.KprobeAttachInfo + (*UprobeAttachInfo)(nil), // 9: bpfman.v1.UprobeAttachInfo + (*FentryAttachInfo)(nil), // 10: bpfman.v1.FentryAttachInfo + (*FexitAttachInfo)(nil), // 11: bpfman.v1.FexitAttachInfo + (*AttachInfo)(nil), // 12: bpfman.v1.AttachInfo + (*LoadRequest)(nil), // 13: bpfman.v1.LoadRequest + (*LoadResponse)(nil), // 14: bpfman.v1.LoadResponse + (*UnloadRequest)(nil), // 15: bpfman.v1.UnloadRequest + (*UnloadResponse)(nil), // 16: bpfman.v1.UnloadResponse + (*ListRequest)(nil), // 17: bpfman.v1.ListRequest + (*ListResponse)(nil), // 18: bpfman.v1.ListResponse + (*PullBytecodeRequest)(nil), // 19: bpfman.v1.PullBytecodeRequest + (*PullBytecodeResponse)(nil), // 20: bpfman.v1.PullBytecodeResponse + (*GetRequest)(nil), // 21: bpfman.v1.GetRequest + (*GetResponse)(nil), // 22: bpfman.v1.GetResponse + nil, // 23: bpfman.v1.ProgramInfo.GlobalDataEntry + nil, // 24: bpfman.v1.ProgramInfo.MetadataEntry + nil, // 25: bpfman.v1.LoadRequest.MetadataEntry + nil, // 26: bpfman.v1.LoadRequest.GlobalDataEntry + nil, // 27: bpfman.v1.ListRequest.MatchMetadataEntry + (*ListResponse_ListResult)(nil), // 28: bpfman.v1.ListResponse.ListResult } var file_bpfman_proto_depIdxs = []int32{ 0, // 0: bpfman.v1.BytecodeLocation.image:type_name -> bpfman.v1.BytecodeImage 1, // 1: bpfman.v1.ProgramInfo.bytecode:type_name -> bpfman.v1.BytecodeLocation - 11, // 2: bpfman.v1.ProgramInfo.attach:type_name -> bpfman.v1.AttachInfo - 22, // 3: bpfman.v1.ProgramInfo.global_data:type_name -> bpfman.v1.ProgramInfo.GlobalDataEntry - 23, // 4: bpfman.v1.ProgramInfo.metadata:type_name -> bpfman.v1.ProgramInfo.MetadataEntry + 12, // 2: bpfman.v1.ProgramInfo.attach:type_name -> bpfman.v1.AttachInfo + 23, // 3: bpfman.v1.ProgramInfo.global_data:type_name -> bpfman.v1.ProgramInfo.GlobalDataEntry + 24, // 4: bpfman.v1.ProgramInfo.metadata:type_name -> bpfman.v1.ProgramInfo.MetadataEntry 4, // 5: bpfman.v1.AttachInfo.xdp_attach_info:type_name -> bpfman.v1.XDPAttachInfo 5, // 6: bpfman.v1.AttachInfo.tc_attach_info:type_name -> bpfman.v1.TCAttachInfo - 6, // 7: bpfman.v1.AttachInfo.tracepoint_attach_info:type_name -> bpfman.v1.TracepointAttachInfo - 7, // 8: bpfman.v1.AttachInfo.kprobe_attach_info:type_name -> bpfman.v1.KprobeAttachInfo - 8, // 9: bpfman.v1.AttachInfo.uprobe_attach_info:type_name -> bpfman.v1.UprobeAttachInfo - 9, // 10: bpfman.v1.AttachInfo.fentry_attach_info:type_name -> bpfman.v1.FentryAttachInfo - 10, // 11: bpfman.v1.AttachInfo.fexit_attach_info:type_name -> bpfman.v1.FexitAttachInfo - 1, // 12: bpfman.v1.LoadRequest.bytecode:type_name -> bpfman.v1.BytecodeLocation - 11, // 13: bpfman.v1.LoadRequest.attach:type_name -> bpfman.v1.AttachInfo - 24, // 14: bpfman.v1.LoadRequest.metadata:type_name -> bpfman.v1.LoadRequest.MetadataEntry - 25, // 15: bpfman.v1.LoadRequest.global_data:type_name -> bpfman.v1.LoadRequest.GlobalDataEntry - 3, // 16: bpfman.v1.LoadResponse.info:type_name -> bpfman.v1.ProgramInfo - 2, // 17: bpfman.v1.LoadResponse.kernel_info:type_name -> bpfman.v1.KernelProgramInfo - 26, // 18: bpfman.v1.ListRequest.match_metadata:type_name -> bpfman.v1.ListRequest.MatchMetadataEntry - 27, // 19: bpfman.v1.ListResponse.results:type_name -> bpfman.v1.ListResponse.ListResult - 0, // 20: bpfman.v1.PullBytecodeRequest.image:type_name -> bpfman.v1.BytecodeImage - 3, // 21: bpfman.v1.GetResponse.info:type_name -> bpfman.v1.ProgramInfo - 2, // 22: bpfman.v1.GetResponse.kernel_info:type_name -> bpfman.v1.KernelProgramInfo - 3, // 23: bpfman.v1.ListResponse.ListResult.info:type_name -> bpfman.v1.ProgramInfo - 2, // 24: bpfman.v1.ListResponse.ListResult.kernel_info:type_name -> bpfman.v1.KernelProgramInfo - 12, // 25: bpfman.v1.Bpfman.Load:input_type -> bpfman.v1.LoadRequest - 14, // 26: bpfman.v1.Bpfman.Unload:input_type -> bpfman.v1.UnloadRequest - 16, // 27: bpfman.v1.Bpfman.List:input_type -> bpfman.v1.ListRequest - 18, // 28: bpfman.v1.Bpfman.PullBytecode:input_type -> bpfman.v1.PullBytecodeRequest - 20, // 29: bpfman.v1.Bpfman.Get:input_type -> bpfman.v1.GetRequest - 13, // 30: bpfman.v1.Bpfman.Load:output_type -> bpfman.v1.LoadResponse - 15, // 31: bpfman.v1.Bpfman.Unload:output_type -> bpfman.v1.UnloadResponse - 17, // 32: bpfman.v1.Bpfman.List:output_type -> bpfman.v1.ListResponse - 19, // 33: bpfman.v1.Bpfman.PullBytecode:output_type -> bpfman.v1.PullBytecodeResponse - 21, // 34: bpfman.v1.Bpfman.Get:output_type -> bpfman.v1.GetResponse - 30, // [30:35] is the sub-list for method output_type - 25, // [25:30] is the sub-list for method input_type - 25, // [25:25] is the sub-list for extension type_name - 25, // [25:25] is the sub-list for extension extendee - 0, // [0:25] is the sub-list for field type_name + 7, // 7: bpfman.v1.AttachInfo.tracepoint_attach_info:type_name -> bpfman.v1.TracepointAttachInfo + 8, // 8: bpfman.v1.AttachInfo.kprobe_attach_info:type_name -> bpfman.v1.KprobeAttachInfo + 9, // 9: bpfman.v1.AttachInfo.uprobe_attach_info:type_name -> bpfman.v1.UprobeAttachInfo + 10, // 10: bpfman.v1.AttachInfo.fentry_attach_info:type_name -> bpfman.v1.FentryAttachInfo + 11, // 11: bpfman.v1.AttachInfo.fexit_attach_info:type_name -> bpfman.v1.FexitAttachInfo + 6, // 12: bpfman.v1.AttachInfo.tcx_attach_info:type_name -> bpfman.v1.TCXAttachInfo + 1, // 13: bpfman.v1.LoadRequest.bytecode:type_name -> bpfman.v1.BytecodeLocation + 12, // 14: bpfman.v1.LoadRequest.attach:type_name -> bpfman.v1.AttachInfo + 25, // 15: bpfman.v1.LoadRequest.metadata:type_name -> bpfman.v1.LoadRequest.MetadataEntry + 26, // 16: bpfman.v1.LoadRequest.global_data:type_name -> bpfman.v1.LoadRequest.GlobalDataEntry + 3, // 17: bpfman.v1.LoadResponse.info:type_name -> bpfman.v1.ProgramInfo + 2, // 18: bpfman.v1.LoadResponse.kernel_info:type_name -> bpfman.v1.KernelProgramInfo + 27, // 19: bpfman.v1.ListRequest.match_metadata:type_name -> bpfman.v1.ListRequest.MatchMetadataEntry + 28, // 20: bpfman.v1.ListResponse.results:type_name -> bpfman.v1.ListResponse.ListResult + 0, // 21: bpfman.v1.PullBytecodeRequest.image:type_name -> bpfman.v1.BytecodeImage + 3, // 22: bpfman.v1.GetResponse.info:type_name -> bpfman.v1.ProgramInfo + 2, // 23: bpfman.v1.GetResponse.kernel_info:type_name -> bpfman.v1.KernelProgramInfo + 3, // 24: bpfman.v1.ListResponse.ListResult.info:type_name -> bpfman.v1.ProgramInfo + 2, // 25: bpfman.v1.ListResponse.ListResult.kernel_info:type_name -> bpfman.v1.KernelProgramInfo + 13, // 26: bpfman.v1.Bpfman.Load:input_type -> bpfman.v1.LoadRequest + 15, // 27: bpfman.v1.Bpfman.Unload:input_type -> bpfman.v1.UnloadRequest + 17, // 28: bpfman.v1.Bpfman.List:input_type -> bpfman.v1.ListRequest + 19, // 29: bpfman.v1.Bpfman.PullBytecode:input_type -> bpfman.v1.PullBytecodeRequest + 21, // 30: bpfman.v1.Bpfman.Get:input_type -> bpfman.v1.GetRequest + 14, // 31: bpfman.v1.Bpfman.Load:output_type -> bpfman.v1.LoadResponse + 16, // 32: bpfman.v1.Bpfman.Unload:output_type -> bpfman.v1.UnloadResponse + 18, // 33: bpfman.v1.Bpfman.List:output_type -> bpfman.v1.ListResponse + 20, // 34: bpfman.v1.Bpfman.PullBytecode:output_type -> bpfman.v1.PullBytecodeResponse + 22, // 35: bpfman.v1.Bpfman.Get:output_type -> bpfman.v1.GetResponse + 31, // [31:36] is the sub-list for method output_type + 26, // [26:31] is the sub-list for method input_type + 26, // [26:26] is the sub-list for extension type_name + 26, // [26:26] is the sub-list for extension extendee + 0, // [0:26] is the sub-list for field type_name } func init() { file_bpfman_proto_init() } @@ -2066,7 +2165,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TracepointAttachInfo); i { + switch v := v.(*TCXAttachInfo); i { case 0: return &v.state case 1: @@ -2078,7 +2177,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*KprobeAttachInfo); i { + switch v := v.(*TracepointAttachInfo); i { case 0: return &v.state case 1: @@ -2090,7 +2189,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UprobeAttachInfo); i { + switch v := v.(*KprobeAttachInfo); i { case 0: return &v.state case 1: @@ -2102,7 +2201,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FentryAttachInfo); i { + switch v := v.(*UprobeAttachInfo); i { case 0: return &v.state case 1: @@ -2114,7 +2213,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FexitAttachInfo); i { + switch v := v.(*FentryAttachInfo); i { case 0: return &v.state case 1: @@ -2126,7 +2225,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AttachInfo); i { + switch v := v.(*FexitAttachInfo); i { case 0: return &v.state case 1: @@ -2138,7 +2237,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LoadRequest); i { + switch v := v.(*AttachInfo); i { case 0: return &v.state case 1: @@ -2150,7 +2249,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LoadResponse); i { + switch v := v.(*LoadRequest); i { case 0: return &v.state case 1: @@ -2162,7 +2261,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UnloadRequest); i { + switch v := v.(*LoadResponse); i { case 0: return &v.state case 1: @@ -2174,7 +2273,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UnloadResponse); i { + switch v := v.(*UnloadRequest); i { case 0: return &v.state case 1: @@ -2186,7 +2285,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListRequest); i { + switch v := v.(*UnloadResponse); i { case 0: return &v.state case 1: @@ -2198,7 +2297,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListResponse); i { + switch v := v.(*ListRequest); i { case 0: return &v.state case 1: @@ -2210,7 +2309,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PullBytecodeRequest); i { + switch v := v.(*ListResponse); i { case 0: return &v.state case 1: @@ -2222,7 +2321,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PullBytecodeResponse); i { + switch v := v.(*PullBytecodeRequest); i { case 0: return &v.state case 1: @@ -2234,7 +2333,7 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetRequest); i { + switch v := v.(*PullBytecodeResponse); i { case 0: return &v.state case 1: @@ -2246,6 +2345,18 @@ func file_bpfman_proto_init() { } } file_bpfman_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bpfman_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -2257,7 +2368,7 @@ func file_bpfman_proto_init() { return nil } } - file_bpfman_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + file_bpfman_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListResponse_ListResult); i { case 0: return &v.state @@ -2276,9 +2387,9 @@ func file_bpfman_proto_init() { (*BytecodeLocation_File)(nil), } file_bpfman_proto_msgTypes[3].OneofWrappers = []interface{}{} - file_bpfman_proto_msgTypes[7].OneofWrappers = []interface{}{} file_bpfman_proto_msgTypes[8].OneofWrappers = []interface{}{} - file_bpfman_proto_msgTypes[11].OneofWrappers = []interface{}{ + file_bpfman_proto_msgTypes[9].OneofWrappers = []interface{}{} + file_bpfman_proto_msgTypes[12].OneofWrappers = []interface{}{ (*AttachInfo_XdpAttachInfo)(nil), (*AttachInfo_TcAttachInfo)(nil), (*AttachInfo_TracepointAttachInfo)(nil), @@ -2286,18 +2397,19 @@ func file_bpfman_proto_init() { (*AttachInfo_UprobeAttachInfo)(nil), (*AttachInfo_FentryAttachInfo)(nil), (*AttachInfo_FexitAttachInfo)(nil), + (*AttachInfo_TcxAttachInfo)(nil), } - file_bpfman_proto_msgTypes[12].OneofWrappers = []interface{}{} - file_bpfman_proto_msgTypes[16].OneofWrappers = []interface{}{} - file_bpfman_proto_msgTypes[21].OneofWrappers = []interface{}{} - file_bpfman_proto_msgTypes[27].OneofWrappers = []interface{}{} + file_bpfman_proto_msgTypes[13].OneofWrappers = []interface{}{} + file_bpfman_proto_msgTypes[17].OneofWrappers = []interface{}{} + file_bpfman_proto_msgTypes[22].OneofWrappers = []interface{}{} + file_bpfman_proto_msgTypes[28].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_bpfman_proto_rawDesc, NumEnums: 0, - NumMessages: 28, + NumMessages: 29, NumExtensions: 0, NumServices: 1, }, diff --git a/vendor/modules.txt b/vendor/modules.txt index 0f4458a7a..2b8842826 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -4,7 +4,7 @@ github.com/beorn7/perks/quantile # github.com/blang/semver/v4 v4.0.0 ## explicit; go 1.14 github.com/blang/semver/v4 -# github.com/bpfman/bpfman v0.5.4 +# github.com/bpfman/bpfman v0.5.5-0.20241022174147-497c1ed71c81 ## explicit; go 1.22.0 github.com/bpfman/bpfman/clients/gobpfman/v1 # github.com/buger/jsonparser v1.1.1 From 5c35e17b8ccfc8ab2d00ee0b85a5ab1d6ad64743 Mon Sep 17 00:00:00 2001 From: Mohamed Mahmoud Date: Tue, 22 Oct 2024 16:39:16 -0400 Subject: [PATCH 6/8] fix intg test for application object Signed-off-by: Mohamed Mahmoud --- test/integration/app_test.go | 1 + test/integration/common.go | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/test/integration/app_test.go b/test/integration/app_test.go index 9922e4481..96704017b 100644 --- a/test/integration/app_test.go +++ b/test/integration/app_test.go @@ -58,6 +58,7 @@ func TestApplicationGoCounter(t *testing.T) { checkFunctions := []func(t *testing.T, output *bytes.Buffer) bool{ doAppKprobeCheck, doAppTcCheck, + doAppTcxCheck, doAppTracepointCheck, doAppUprobeCheck, doAppXdpCheck, diff --git a/test/integration/common.go b/test/integration/common.go index 3ffe4a086..9b76c6958 100644 --- a/test/integration/common.go +++ b/test/integration/common.go @@ -40,8 +40,18 @@ func doTcCheck(t *testing.T, output *bytes.Buffer) bool { } func doAppTcCheck(t *testing.T, output *bytes.Buffer) bool { - if strings.Contains(output.String(), "TC:") && strings.Contains(output.String(), "packets received") && strings.Contains(output.String(), "bytes received") { - t.Log("TC BPF program is functioning") + str := `TC: received (\d+) packets` + if ok, count := doProbeCommonCheck(t, output, str); ok { + t.Logf("TC BPF program is functioning packets: %d", count) + return true + } + return false +} + +func doAppTcxCheck(t *testing.T, output *bytes.Buffer) bool { + str := `TCX: received (\d+) packets` + if ok, count := doProbeCommonCheck(t, output, str); ok { + t.Logf("TCX BPF program is functioning packets: %d", count) return true } return false @@ -92,8 +102,9 @@ func doXdpCheck(t *testing.T, output *bytes.Buffer) bool { } func doAppXdpCheck(t *testing.T, output *bytes.Buffer) bool { - if strings.Contains(output.String(), "XDP:") && strings.Contains(output.String(), "packets received") && strings.Contains(output.String(), "bytes received") { - t.Log("XDP BPF program is functioning") + str := `XDP: received (\d+) packets` + if ok, count := doProbeCommonCheck(t, output, str); ok { + t.Logf("XDP BPF program is functioning packets: %d", count) return true } return false From 875131f914814f7976c562678c8a2ac5e010cf1f Mon Sep 17 00:00:00 2001 From: Mohamed Mahmoud Date: Tue, 22 Oct 2024 17:07:35 -0400 Subject: [PATCH 7/8] change GH workflows from ubuntu latest to ubuntu-24.04 Signed-off-by: Mohamed Mahmoud --- .github/workflows/image-build.yaml | 4 ++-- .github/workflows/integration_test.yml | 2 +- .github/workflows/pull_request.yml | 8 ++++---- .github/workflows/release.yml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/image-build.yaml b/.github/workflows/image-build.yaml index 458eaf687..9bcbf0812 100644 --- a/.github/workflows/image-build.yaml +++ b/.github/workflows/image-build.yaml @@ -19,7 +19,7 @@ jobs: packages: write id-token: write # needed for signing the images with GitHub OIDC Token - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: @@ -114,7 +114,7 @@ jobs: packages: write id-token: write # needed for signing the images with GitHub OIDC Token - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index e57d82e30..5d7ccaf49 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -11,7 +11,7 @@ jobs: kubernetes-integration-tests: name: Kubernetes Integration Tests (Go ${{ matrix.go }} - amd64 - ${{ matrix.oci_bin }}) - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: matrix: go: ['1.22'] diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 266c23679..dd70144aa 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -7,7 +7,7 @@ on: jobs: check-license: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 3 steps: @@ -17,7 +17,7 @@ jobs: build-lint-test: name: Build (Go ${{ matrix.go }} - ${{ matrix.arch.arch }}) - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: @@ -79,7 +79,7 @@ jobs: coverage: needs: [build-lint-test] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Download golang coverage artifacts uses: actions/download-artifact@v4 @@ -103,7 +103,7 @@ jobs: build-lint-test, coverage, ] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Build Complete run: echo "Build Complete" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d71998fbd..8a5158480 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ jobs: # Creates Release with just the changelog release: if: startsWith(github.ref, 'refs/tags/v') - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout bpfman uses: actions/checkout@v4 From aa3840dc424b563a6a7feda9b2cc1b66b3a4eaed Mon Sep 17 00:00:00 2001 From: Mohamed Mahmoud Date: Wed, 23 Oct 2024 09:41:49 -0400 Subject: [PATCH 8/8] Address review comments Signed-off-by: Mohamed Mahmoud --- apis/v1alpha1/tcxProgram_types.go | 1 + bundle/manifests/bpfman.io_tcxprograms.yaml | 4 ++++ config/crd/bases/bpfman.io_tcxprograms.yaml | 4 ++++ controllers/bpfman-operator/tcx-program.go | 8 ++++---- test/integration/common.go | 8 ++++++++ test/integration/tcx_test.go | 6 +++--- 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/apis/v1alpha1/tcxProgram_types.go b/apis/v1alpha1/tcxProgram_types.go index 31f2b223e..08648ae87 100644 --- a/apis/v1alpha1/tcxProgram_types.go +++ b/apis/v1alpha1/tcxProgram_types.go @@ -35,6 +35,7 @@ import ( // +kubebuilder:printcolumn:name="Direction",type=string,JSONPath=`.spec.direction`,priority=1 // +kubebuilder:printcolumn:name="InterfaceSelector",type=string,JSONPath=`.spec.interfaceselector`,priority=1 // +kubebuilder:printcolumn:name="Position",type=string,JSONPath=`.spec.position`,priority=1 +// +kubebuilder:printcolumn:name="Priority",type=string,JSONPath=`.spec.priority`,priority=1 type TcxProgram struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/bundle/manifests/bpfman.io_tcxprograms.yaml b/bundle/manifests/bpfman.io_tcxprograms.yaml index 4aeb98cd2..e230c0dac 100644 --- a/bundle/manifests/bpfman.io_tcxprograms.yaml +++ b/bundle/manifests/bpfman.io_tcxprograms.yaml @@ -36,6 +36,10 @@ spec: name: Position priority: 1 type: string + - jsonPath: .spec.priority + name: Priority + priority: 1 + type: string name: v1alpha1 schema: openAPIV3Schema: diff --git a/config/crd/bases/bpfman.io_tcxprograms.yaml b/config/crd/bases/bpfman.io_tcxprograms.yaml index 31a6d8480..5b813f761 100644 --- a/config/crd/bases/bpfman.io_tcxprograms.yaml +++ b/config/crd/bases/bpfman.io_tcxprograms.yaml @@ -36,6 +36,10 @@ spec: name: Position priority: 1 type: string + - jsonPath: .spec.priority + name: Priority + priority: 1 + type: string name: v1alpha1 schema: openAPIV3Schema: diff --git a/controllers/bpfman-operator/tcx-program.go b/controllers/bpfman-operator/tcx-program.go index 2de7d297b..05a9925fd 100644 --- a/controllers/bpfman-operator/tcx-program.go +++ b/controllers/bpfman-operator/tcx-program.go @@ -47,7 +47,7 @@ func (r *TcxProgramReconciler) getFinalizer() string { func (r *TcxProgramReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&bpfmaniov1alpha1.TcxProgram{}). - // Watch bpfPrograms which are owned by TcPrograms + // Watch bpfPrograms which are owned by TcxPrograms Watches( &bpfmaniov1alpha1.BpfProgram{}, &handler.EnqueueRequestForObject{}, @@ -65,7 +65,7 @@ func (r *TcxProgramReconciler) Reconcile(ctx context.Context, req ctrl.Request) tcxProgram := &bpfmaniov1alpha1.TcxProgram{} if err := r.Get(ctx, req.NamespacedName, tcxProgram); err != nil { - // list all TcProgram objects with + // list all TcxProgram objects with if errors.IsNotFound(err) { bpfProgram := &bpfmaniov1alpha1.BpfProgram{} if err := r.Get(ctx, req.NamespacedName, bpfProgram); err != nil { @@ -87,7 +87,7 @@ func (r *TcxProgramReconciler) Reconcile(ctx context.Context, req ctrl.Request) if errors.IsNotFound(err) { r.Logger.Info("tcxProgram from ownerRef not found stale reconcile exiting", "Name", req.NamespacedName) } else { - r.Logger.Error(err, "failed getting TcProgram Object from ownerRef", "Name", req.NamespacedName) + r.Logger.Error(err, "failed getting TcxProgram Object from ownerRef", "Name", req.NamespacedName) } return ctrl.Result{}, nil } @@ -102,7 +102,7 @@ func (r *TcxProgramReconciler) Reconcile(ctx context.Context, req ctrl.Request) } func (r *TcxProgramReconciler) updateStatus(ctx context.Context, name string, cond bpfmaniov1alpha1.ProgramConditionType, message string) (ctrl.Result, error) { - // Sometimes we end up with a stale TcProgram due to races, do this + // Sometimes we end up with a stale TcxProgram due to races, do this // get to ensure we're up to date before attempting a finalizer removal. prog := &bpfmaniov1alpha1.TcxProgram{} if err := r.Get(ctx, types.NamespacedName{Namespace: corev1.NamespaceAll, Name: name}, prog); err != nil { diff --git a/test/integration/common.go b/test/integration/common.go index 9b76c6958..56efdf241 100644 --- a/test/integration/common.go +++ b/test/integration/common.go @@ -48,6 +48,14 @@ func doAppTcCheck(t *testing.T, output *bytes.Buffer) bool { return false } +func doTcxCheck(t *testing.T, output *bytes.Buffer) bool { + if strings.Contains(output.String(), "packets received") && strings.Contains(output.String(), "bytes received") { + t.Log("TCX BPF program is functioning") + return true + } + return false +} + func doAppTcxCheck(t *testing.T, output *bytes.Buffer) bool { str := `TCX: received (\d+) packets` if ok, count := doProbeCommonCheck(t, output, str); ok { diff --git a/test/integration/tcx_test.go b/test/integration/tcx_test.go index 609dbca3b..e6648f5dd 100644 --- a/test/integration/tcx_test.go +++ b/test/integration/tcx_test.go @@ -41,9 +41,9 @@ func TestTcxGoCounter(t *testing.T) { pods, err := env.Cluster().Client().CoreV1().Pods(tcxGoCounterUserspaceNs).List(ctx, metav1.ListOptions{LabelSelector: "name=go-tcx-counter"}) require.NoError(t, err) - gotcCounterPod := pods.Items[0] + gotcxCounterPod := pods.Items[0] - req := env.Cluster().Client().CoreV1().Pods(tcxGoCounterUserspaceNs).GetLogs(gotcCounterPod.Name, &corev1.PodLogOptions{}) + req := env.Cluster().Client().CoreV1().Pods(tcxGoCounterUserspaceNs).GetLogs(gotcxCounterPod.Name, &corev1.PodLogOptions{}) require.Eventually(t, func() bool { logs, err := req.Stream(ctx) @@ -54,6 +54,6 @@ func TestTcxGoCounter(t *testing.T) { require.NoError(t, err) t.Logf("counter pod log %s", output.String()) - return doTcCheck(t, output) + return doTcxCheck(t, output) }, 30*time.Second, time.Second) }