From a5403d403cdd170eed053bda34cae7f98ce96858 Mon Sep 17 00:00:00 2001 From: Robert Gildein Date: Tue, 8 Sep 2026 17:02:32 +0200 Subject: [PATCH] Add PIM logNeighborChanges to PimConfig NX-OS CRD Add custom PimConfig with NX-OS api version to configure logNeighborChanges (logNbhChng) on Cisco device. Signed-off-by: Robert Gildein --- PROJECT | 8 ++ api/cisco/nx/v1alpha1/pim_types.go | 53 +++++++++++++ .../nx/v1alpha1/zz_generated.deepcopy.go | 78 +++++++++++++++++++ .../templates/rbac/manager-role.yaml | 1 + ...working.metal.ironcore.dev_pimconfigs.yaml | 51 ++++++++++++ config/rbac/role.yaml | 1 + .../samples/cisco/nx/v1alpha1_pimconfig.yaml | 9 +++ config/samples/v1alpha1_pim.yaml | 6 ++ docs/api-reference/index.md | 35 +++++++++ internal/provider/cisco/nxos/pim.go | 5 +- internal/provider/cisco/nxos/pim_test.go | 7 ++ internal/provider/cisco/nxos/provider.go | 8 ++ .../cisco/nxos/testdata/pim_dom_log.json | 15 ++++ .../cisco/nxos/testdata/pim_dom_log.json.txt | 1 + .../pim.txtar | 14 ++++ 15 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 api/cisco/nx/v1alpha1/pim_types.go create mode 100644 config/crd/bases/nx.cisco.networking.metal.ironcore.dev_pimconfigs.yaml create mode 100644 config/samples/cisco/nx/v1alpha1_pimconfig.yaml create mode 100644 internal/provider/cisco/nxos/testdata/pim_dom_log.json create mode 100644 internal/provider/cisco/nxos/testdata/pim_dom_log.json.txt diff --git a/PROJECT b/PROJECT index c5a6f881d..f67d9f710 100644 --- a/PROJECT +++ b/PROJECT @@ -285,6 +285,14 @@ resources: kind: BGPConfig path: github.com/ironcore-dev/network-operator/api/cisco/nx/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: cisco.networking.metal.ironcore.dev + group: nx + kind: PIMConfig + path: github.com/ironcore-dev/network-operator/api/cisco/nx/v1alpha1 + version: v1alpha1 - api: crdVersion: v1 namespaced: true diff --git a/api/cisco/nx/v1alpha1/pim_types.go b/api/cisco/nx/v1alpha1/pim_types.go new file mode 100644 index 000000000..074fd4484 --- /dev/null +++ b/api/cisco/nx/v1alpha1/pim_types.go @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2026 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + v1alpha1 "github.com/ironcore-dev/network-operator/api/core/v1alpha1" +) + +// +kubebuilder:rbac:groups=nx.cisco.networking.metal.ironcore.dev,resources=pimconfigs,verbs=get;list;watch + +// PIMConfigSpec defines the Cisco NX-OS specific PIM configuration. +type PIMConfigSpec struct { + // LogNeighborChanges enables logging when a PIM neighbor is added or removed. + // +optional + LogNeighborChanges *bool `json:"logNeighborChanges,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=pimconfigs +// +kubebuilder:resource:singular=pimconfig + +// PIMConfig is the Schema for the PIMConfig API +type PIMConfig struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty,omitzero"` + + // spec defines the desired state of PIMConfig + // +required + Spec PIMConfigSpec `json:"spec"` +} + +// +kubebuilder:object:root=true + +// PIMConfigList contains a list of PIMConfigs +type PIMConfigList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PIMConfig `json:"items"` +} + +// init registers the PIMConfig type with the scheme and sets +// itself as a dependency for the PIM core type. +func init() { + v1alpha1.RegisterPIMDependency(GroupVersion.WithKind("PIMConfig")) + SchemeBuilder.Register(func(s *runtime.Scheme) error { + s.AddKnownTypes(GroupVersion, &PIMConfig{}, &PIMConfigList{}) + return nil + }) +} diff --git a/api/cisco/nx/v1alpha1/zz_generated.deepcopy.go b/api/cisco/nx/v1alpha1/zz_generated.deepcopy.go index 1475968f6..12224806f 100644 --- a/api/cisco/nx/v1alpha1/zz_generated.deepcopy.go +++ b/api/cisco/nx/v1alpha1/zz_generated.deepcopy.go @@ -845,6 +845,84 @@ func (in *NetworkVirtualizationEdgeConfigSpec) DeepCopy() *NetworkVirtualization return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PIMConfig) DeepCopyInto(out *PIMConfig) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PIMConfig. +func (in *PIMConfig) DeepCopy() *PIMConfig { + if in == nil { + return nil + } + out := new(PIMConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PIMConfig) 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 *PIMConfigList) DeepCopyInto(out *PIMConfigList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PIMConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PIMConfigList. +func (in *PIMConfigList) DeepCopy() *PIMConfigList { + if in == nil { + return nil + } + out := new(PIMConfigList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PIMConfigList) 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 *PIMConfigSpec) DeepCopyInto(out *PIMConfigSpec) { + *out = *in + if in.LogNeighborChanges != nil { + in, out := &in.LogNeighborChanges, &out.LogNeighborChanges + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PIMConfigSpec. +func (in *PIMConfigSpec) DeepCopy() *PIMConfigSpec { + if in == nil { + return nil + } + out := new(PIMConfigSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Peer) DeepCopyInto(out *Peer) { *out = *in diff --git a/charts/network-operator/templates/rbac/manager-role.yaml b/charts/network-operator/templates/rbac/manager-role.yaml index 79729cf5f..8c4b0acd6 100644 --- a/charts/network-operator/templates/rbac/manager-role.yaml +++ b/charts/network-operator/templates/rbac/manager-role.yaml @@ -185,6 +185,7 @@ rules: - lldpconfigs - managementaccessconfigs - networkvirtualizationedgeconfigs + - pimconfigs verbs: - get - list diff --git a/config/crd/bases/nx.cisco.networking.metal.ironcore.dev_pimconfigs.yaml b/config/crd/bases/nx.cisco.networking.metal.ironcore.dev_pimconfigs.yaml new file mode 100644 index 000000000..763951fbc --- /dev/null +++ b/config/crd/bases/nx.cisco.networking.metal.ironcore.dev_pimconfigs.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.22.0 + name: pimconfigs.nx.cisco.networking.metal.ironcore.dev +spec: + group: nx.cisco.networking.metal.ironcore.dev + names: + kind: PIMConfig + listKind: PIMConfigList + plural: pimconfigs + singular: pimconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: PIMConfig is the Schema for the PIMConfig 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: spec defines the desired state of PIMConfig + properties: + logNeighborChanges: + description: LogNeighborChanges enables logging when a PIM neighbor + is added or removed. + type: boolean + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 66cdebb60..3ce8c6af7 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -179,6 +179,7 @@ rules: - lldpconfigs - managementaccessconfigs - networkvirtualizationedgeconfigs + - pimconfigs verbs: - get - list diff --git a/config/samples/cisco/nx/v1alpha1_pimconfig.yaml b/config/samples/cisco/nx/v1alpha1_pimconfig.yaml new file mode 100644 index 000000000..bb84f8182 --- /dev/null +++ b/config/samples/cisco/nx/v1alpha1_pimconfig.yaml @@ -0,0 +1,9 @@ +apiVersion: nx.cisco.networking.metal.ironcore.dev/v1alpha1 +kind: PIMConfig +metadata: + labels: + app.kubernetes.io/name: network-operator + app.kubernetes.io/managed-by: kustomize + name: leaf1-pimconfig +spec: + logNeighborChanges: true diff --git a/config/samples/v1alpha1_pim.yaml b/config/samples/v1alpha1_pim.yaml index bbcf2ad57..6a2af0ac9 100644 --- a/config/samples/v1alpha1_pim.yaml +++ b/config/samples/v1alpha1_pim.yaml @@ -9,6 +9,12 @@ metadata: spec: deviceRef: name: leaf1 + # Uncomment to add NXOS provider-specific config + # See: ./cisco/nx/v1alpha1_pimconfig.yaml + # providerConfigRef: + # apiVersion: nx.cisco.networking.metal.ironcore.dev/v1alpha1 + # kind: PIMConfig + # name: leaf1-pimconfig rendezvousPoints: - address: 10.0.0.100 multicastGroups: diff --git a/docs/api-reference/index.md b/docs/api-reference/index.md index fef20cbf9..2e5b7eb22 100644 --- a/docs/api-reference/index.md +++ b/docs/api-reference/index.md @@ -4577,6 +4577,7 @@ Package v1alpha1 contains API Schema definitions for the nx.cisco.networking.met - [LLDPConfig](#lldpconfig) - [ManagementAccessConfig](#managementaccessconfig) - [NetworkVirtualizationEdgeConfig](#networkvirtualizationedgeconfig) +- [PIMConfig](#pimconfig) - [System](#system) - [VPCDomain](#vpcdomain) @@ -5097,6 +5098,40 @@ _Appears in:_ | `infraVLANs` _[VLANListItem](#vlanlistitem) array_ | InfraVLANs specifies VLANs used by all SVI interfaces for uplink and vPC peer-links in VXLAN as infra-VLANs.
Valid VLAN IDs are 1-4092 because NX-OS always reserves VLANs 4093-4095 for internal use.
The provider also checks these VLANs against the device's configurable internal reserved VLAN range.
The total number of VLANs configured must not exceed 512.
Elements in the list must not overlap with each other. | | MaxItems: 10
Optional: \{\}
| +#### PIMConfig + + + +PIMConfig is the Schema for the PIMConfig API + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `nx.cisco.networking.metal.ironcore.dev/v1alpha1` | | | +| `kind` _string_ | `PIMConfig` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[PIMConfigSpec](#pimconfigspec)_ | spec defines the desired state of PIMConfig | | Required: \{\}
| + + +#### PIMConfigSpec + + + +PIMConfigSpec defines the Cisco NX-OS specific PIM configuration. + + + +_Appears in:_ +- [PIMConfig](#pimconfig) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `logNeighborChanges` _boolean_ | LogNeighborChanges enables logging when a PIM neighbor is added or removed. | | Optional: \{\}
| + + #### Peer diff --git a/internal/provider/cisco/nxos/pim.go b/internal/provider/cisco/nxos/pim.go index c484ada9c..80148c7e4 100644 --- a/internal/provider/cisco/nxos/pim.go +++ b/internal/provider/cisco/nxos/pim.go @@ -27,8 +27,9 @@ func (*PIM) XPath() string { } type PIMDom struct { - Name string `json:"name"` - AdminSt AdminSt `json:"adminSt"` + Name string `json:"name"` + AdminSt AdminSt `json:"adminSt"` + LogNbhChng *bool `json:"logNbhChng,omitempty"` } func (*PIMDom) IsListItem() {} diff --git a/internal/provider/cisco/nxos/pim_test.go b/internal/provider/cisco/nxos/pim_test.go index 6a5430b9b..53908497c 100644 --- a/internal/provider/cisco/nxos/pim_test.go +++ b/internal/provider/cisco/nxos/pim_test.go @@ -15,4 +15,11 @@ func init() { rp := &StaticRP{Addr: "10.0.0.100/32"} rp.RpgrplistItems.RPGrpListList.Set(&StaticRPGrp{GrpListName: "224.0.0.0/4"}) Register("pim_rp", rp) + + logEnabled := true + Register("pim_dom_log", &PIMDom{ + Name: "default", + AdminSt: AdminStEnabled, + LogNbhChng: &logEnabled, + }) } diff --git a/internal/provider/cisco/nxos/provider.go b/internal/provider/cisco/nxos/provider.go index 4001c4aa4..a1c63df2a 100644 --- a/internal/provider/cisco/nxos/provider.go +++ b/internal/provider/cisco/nxos/provider.go @@ -2429,6 +2429,13 @@ func (p *Provider) EnsurePIM(ctx context.Context, req *provider.EnsurePIMRequest f.AdminSt = AdminStEnabled sb.Update(f) + var cfg nxv1alpha1.PIMConfig + if req.ProviderConfig != nil { + if err := req.ProviderConfig.Into(&cfg); err != nil { + return err + } + } + pim := new(PIM) pim.AdminSt = AdminStEnabled pim.InstItems.AdminSt = AdminStEnabled @@ -2444,6 +2451,7 @@ func (p *Provider) EnsurePIM(ctx context.Context, req *provider.EnsurePIMRequest if req.PIM.Spec.AdminState == v1alpha1.AdminStateDown { dom.AdminSt = AdminStDisabled } + dom.LogNbhChng = cfg.Spec.LogNeighborChanges sb.Patch(dom) rpItems := new(StaticRPItems) diff --git a/internal/provider/cisco/nxos/testdata/pim_dom_log.json b/internal/provider/cisco/nxos/testdata/pim_dom_log.json new file mode 100644 index 000000000..19897345f --- /dev/null +++ b/internal/provider/cisco/nxos/testdata/pim_dom_log.json @@ -0,0 +1,15 @@ +{ + "pim-items": { + "inst-items": { + "dom-items": { + "Dom-list": [ + { + "name": "default", + "adminSt": "enabled", + "logNbhChng": true + } + ] + } + } + } +} diff --git a/internal/provider/cisco/nxos/testdata/pim_dom_log.json.txt b/internal/provider/cisco/nxos/testdata/pim_dom_log.json.txt new file mode 100644 index 000000000..6e73f1ae5 --- /dev/null +++ b/internal/provider/cisco/nxos/testdata/pim_dom_log.json.txt @@ -0,0 +1 @@ +ip pim log-neighbor-changes diff --git a/test/gnmi/testdata/nx.cisco.networking.metal.ironcore.dev/pim.txtar b/test/gnmi/testdata/nx.cisco.networking.metal.ironcore.dev/pim.txtar index 2ada9693f..170c6c4ac 100644 --- a/test/gnmi/testdata/nx.cisco.networking.metal.ironcore.dev/pim.txtar +++ b/test/gnmi/testdata/nx.cisco.networking.metal.ironcore.dev/pim.txtar @@ -14,6 +14,15 @@ spec: addresses: - 10.255.255.20/32 +-- pimconfigs/log-neighbor -- +apiVersion: nx.cisco.networking.metal.ironcore.dev/v1alpha1 +kind: PIMConfig +metadata: + name: log-neighbor + namespace: default +spec: + logNeighborChanges: true + -- pims/multicast -- apiVersion: networking.metal.ironcore.dev/v1alpha1 kind: PIM @@ -24,6 +33,10 @@ spec: deviceRef: name: device adminState: Up + providerConfigRef: + apiVersion: nx.cisco.networking.metal.ironcore.dev/v1alpha1 + kind: PIMConfig + name: log-neighbor interfaceRefs: - name: lo-pim mode: Sparse @@ -119,6 +132,7 @@ spec: { "name": "default", "adminSt": "enabled", + "logNbhChng": true, "if-items": { "If-list": [ {