diff --git a/api/core/v1alpha1/evpninstance_types.go b/api/core/v1alpha1/evpninstance_types.go index d38fb01b7..be03ab3e1 100644 --- a/api/core/v1alpha1/evpninstance_types.go +++ b/api/core/v1alpha1/evpninstance_types.go @@ -85,6 +85,11 @@ type EVPNInstanceSpec struct { // +optional // +kubebuilder:validation:XValidation:rule="self.name == oldSelf.name",message="VRFRef is immutable" VRFRef *LocalObjectReference `json:"vrfRef,omitempty"` + + // SuppressARP overrides the NVE-level ARP suppression setting for this VNI. + // When unset, the NVE-level SuppressARP setting takes precedence. + // +optional + SuppressARP *bool `json:"suppressARP,omitempty"` } // EVPNInstanceType defines the type of EVPN instance. diff --git a/api/core/v1alpha1/zz_generated.deepcopy.go b/api/core/v1alpha1/zz_generated.deepcopy.go index 1ab6b9e18..ef9944b4a 100644 --- a/api/core/v1alpha1/zz_generated.deepcopy.go +++ b/api/core/v1alpha1/zz_generated.deepcopy.go @@ -2049,6 +2049,11 @@ func (in *EVPNInstanceSpec) DeepCopyInto(out *EVPNInstanceSpec) { *out = new(LocalObjectReference) **out = **in } + if in.SuppressARP != nil { + in, out := &in.SuppressARP, &out.SuppressARP + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EVPNInstanceSpec. diff --git a/charts/network-operator/templates/crd/evpninstances.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/evpninstances.networking.metal.ironcore.dev.yaml index 519d3d2d4..7a91dc3eb 100644 --- a/charts/network-operator/templates/crd/evpninstances.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/evpninstances.networking.metal.ironcore.dev.yaml @@ -168,6 +168,11 @@ spec: x-kubernetes-list-map-keys: - value x-kubernetes-list-type: map + suppressARP: + description: |- + SuppressARP overrides the NVE-level ARP suppression setting for this VNI. + When unset, the NVE-level SuppressARP setting takes precedence. + type: boolean type: description: |- Type specifies the EVPN instance type. diff --git a/config/crd/bases/networking.metal.ironcore.dev_evpninstances.yaml b/config/crd/bases/networking.metal.ironcore.dev_evpninstances.yaml index 8ee981b5f..f0d04fb02 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_evpninstances.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_evpninstances.yaml @@ -165,6 +165,11 @@ spec: x-kubernetes-list-map-keys: - value x-kubernetes-list-type: map + suppressARP: + description: |- + SuppressARP overrides the NVE-level ARP suppression setting for this VNI. + When unset, the NVE-level SuppressARP setting takes precedence. + type: boolean type: description: |- Type specifies the EVPN instance type. diff --git a/docs/api-reference/index.md b/docs/api-reference/index.md index ed271ca0e..d4d8a6b3e 100644 --- a/docs/api-reference/index.md +++ b/docs/api-reference/index.md @@ -1943,6 +1943,7 @@ _Appears in:_ | `routeTargets` _[EVPNRouteTarget](#evpnroutetarget) array_ | RouteTargets is the list of route targets for the EVI. | | MinItems: 1
Optional: \{\}
| | `vlanRef` _[LocalObjectReference](#localobjectreference)_ | VLANRef is a reference to a VLAN resource for which this EVPNInstance builds the MAC-VRF.
This field is only applicable when Type is Bridged (L2VNI).
The VLAN resource must exist in the same namespace.
Immutable. | | Optional: \{\}
| | `vrfRef` _[LocalObjectReference](#localobjectreference)_ | VRFRef is a reference to a VRF resource for which this EVPNInstance provides the L3VNI.
This field is only applicable when Type is Routed (L3VNI).
The VRF resource must exist in the same namespace.
Immutable. | | Optional: \{\}
| +| `suppressARP` _boolean_ | SuppressARP overrides the NVE-level ARP suppression setting for this VNI.
When unset, the NVE-level SuppressARP setting takes precedence. | | Optional: \{\}
| #### EVPNInstanceStatus diff --git a/internal/provider/cisco/nxos/nve.go b/internal/provider/cisco/nxos/nve.go index cb46c33e7..70a7f15fb 100644 --- a/internal/provider/cisco/nxos/nve.go +++ b/internal/provider/cisco/nxos/nve.go @@ -68,6 +68,7 @@ type VNI struct { AssociateVrfFlag bool `json:"associateVrfFlag"` McastGroup Option[string] `json:"mcastGroup"` Vni int32 `json:"vni"` + SuppressARP Option[bool] `json:"suppressARP"` } func (*VNI) IsListItem() {} diff --git a/internal/provider/cisco/nxos/nve_test.go b/internal/provider/cisco/nxos/nve_test.go index 3a545f767..dc7c856a9 100644 --- a/internal/provider/cisco/nxos/nve_test.go +++ b/internal/provider/cisco/nxos/nve_test.go @@ -22,6 +22,20 @@ func init() { McastGroup: NewOption("239.1.1.100"), } Register("vni", vni) + + suppressARPTrue := true + vniSuppressARPTrue := &VNI{ + Vni: 100011, + SuppressARP: Option[bool]{Value: &suppressARPTrue}, + } + Register("vni_suppress_arp_true", vniSuppressARPTrue) + + suppressARPFalse := false + vniSuppressARPFalse := &VNI{ + Vni: 100012, + SuppressARP: Option[bool]{Value: &suppressARPFalse}, + } + Register("vni_suppress_arp_false", vniSuppressARPFalse) nveInfraVLANs := &NVEInfraVLANs{ InfraVLANList: []*NVEInfraVLAN{ {ID: 4052}, diff --git a/internal/provider/cisco/nxos/option.go b/internal/provider/cisco/nxos/option.go index 7e70ee4e8..3a938a1c1 100644 --- a/internal/provider/cisco/nxos/option.go +++ b/internal/provider/cisco/nxos/option.go @@ -33,7 +33,7 @@ func (o Option[T]) MarshalJSON() ([]byte, error) { } func (o *Option[T]) UnmarshalJSON(b []byte) error { - if len(b) == 0 || string(b) == `null` { + if len(b) == 0 || string(b) == `null` || string(b) == `"DME_UNSET_PROPERTY_MARKER"` { o.Value = nil return nil } diff --git a/internal/provider/cisco/nxos/provider.go b/internal/provider/cisco/nxos/provider.go index 4e1fc96b9..21288b5ee 100644 --- a/internal/provider/cisco/nxos/provider.go +++ b/internal/provider/cisco/nxos/provider.go @@ -1117,6 +1117,10 @@ func (p *Provider) EnsureEVPNInstance(ctx context.Context, req *provider.EVPNIns if req.EVPNInstance.Spec.MulticastGroupAddress != "" { vni.McastGroup = NewOption(req.EVPNInstance.Spec.MulticastGroupAddress) } + if req.EVPNInstance.Spec.SuppressARP != nil { + v := *req.EVPNInstance.Spec.SuppressARP + vni.SuppressARP = Option[bool]{Value: &v} + } sb.Update(vni) switch req.EVPNInstance.Spec.Type { diff --git a/internal/provider/cisco/nxos/testdata/vni.json b/internal/provider/cisco/nxos/testdata/vni.json index 8f4e8cfe0..1792184e5 100644 --- a/internal/provider/cisco/nxos/testdata/vni.json +++ b/internal/provider/cisco/nxos/testdata/vni.json @@ -10,7 +10,8 @@ { "associateVrfFlag": false, "mcastGroup": "239.1.1.100", - "vni": 100010 + "vni": 100010, + "suppressARP": "DME_UNSET_PROPERTY_MARKER" } ] } diff --git a/internal/provider/cisco/nxos/testdata/vni_suppress_arp_false.json b/internal/provider/cisco/nxos/testdata/vni_suppress_arp_false.json new file mode 100644 index 000000000..5223aff2d --- /dev/null +++ b/internal/provider/cisco/nxos/testdata/vni_suppress_arp_false.json @@ -0,0 +1,23 @@ +{ + "eps-items": { + "epId-items": { + "Ep-list": [ + { + "epId": "1", + "nws-items": { + "vni-items": { + "Nw-list": [ + { + "associateVrfFlag": false, + "mcastGroup": "DME_UNSET_PROPERTY_MARKER", + "vni": 100012, + "suppressARP": false + } + ] + } + } + } + ] + } + } +} diff --git a/internal/provider/cisco/nxos/testdata/vni_suppress_arp_true.json b/internal/provider/cisco/nxos/testdata/vni_suppress_arp_true.json new file mode 100644 index 000000000..2528b3c06 --- /dev/null +++ b/internal/provider/cisco/nxos/testdata/vni_suppress_arp_true.json @@ -0,0 +1,23 @@ +{ + "eps-items": { + "epId-items": { + "Ep-list": [ + { + "epId": "1", + "nws-items": { + "vni-items": { + "Nw-list": [ + { + "associateVrfFlag": false, + "mcastGroup": "DME_UNSET_PROPERTY_MARKER", + "vni": 100011, + "suppressARP": true + } + ] + } + } + } + ] + } + } +} diff --git a/test/gnmi/testdata/cisco-nxos-gnmi/evpninstance.txtar b/test/gnmi/testdata/cisco-nxos-gnmi/evpninstance.txtar index fd0fae846..0a275a34b 100644 --- a/test/gnmi/testdata/cisco-nxos-gnmi/evpninstance.txtar +++ b/test/gnmi/testdata/cisco-nxos-gnmi/evpninstance.txtar @@ -86,7 +86,8 @@ spec: { "associateVrfFlag": false, "mcastGroup": "DME_UNSET_PROPERTY_MARKER", - "vni": 10100 + "vni": 10100, + "suppressARP": "DME_UNSET_PROPERTY_MARKER" } ] }