diff --git a/api/core/v1alpha1/interface_types.go b/api/core/v1alpha1/interface_types.go index 8097bb7d6..ab17e88e3 100644 --- a/api/core/v1alpha1/interface_types.go +++ b/api/core/v1alpha1/interface_types.go @@ -25,6 +25,9 @@ import ( // +kubebuilder:validation:XValidation:rule="self.type != 'Aggregate' || !has(self.switchport) || !has(self.vrfRef)", message="vrfRef must not be specified for Aggregate interfaces with switchport configuration" // +kubebuilder:validation:XValidation:rule="self.type != 'Physical' || !has(self.switchport) || !has(self.vrfRef)", message="vrfRef must not be specified for Physical interfaces with switchport configuration" // +kubebuilder:validation:XValidation:rule="self.type != 'Aggregate' || !has(self.switchport) || !has(self.bfd)", message="bfd must not be specified for Aggregate interfaces with switchport configuration" +// +kubebuilder:validation:XValidation:rule="self.type == 'Subinterface' || !(has(self.encapsulation) || has(self.parentInterfaceRef))", message="encapsulation and parentInterfaceRef must only be specified for subinterfaces" +// +kubebuilder:validation:XValidation:rule="self.type != 'Subinterface' || !(has(self.aggregation) || has(self.switchport) || has(self.vlanRef))", message="subinterface must not have aggregation, switchport or vlanRef configuration" +// +kubebuilder:validation:XValidation:rule="self.type != 'Subinterface' || (has(self.encapsulation) && has(self.parentInterfaceRef))", message="encapsulation and parentInterfaceRef must both be specified for subinterfaces" // +kubebuilder:validation:XValidation:rule="!has(self.bfd) || !has(self.switchport)", message="bfd must not be specified for interfaces with switchport configuration" // +kubebuilder:validation:XValidation:rule="self.type == 'Physical' || !has(self.ethernet)", message="ethernet configuration must only be specified on interfaces of type Physical" type InterfaceSpec struct { @@ -104,6 +107,15 @@ type InterfaceSpec struct { // When omitted, ethernet parameters use their default values (e.g., FEC mode defaults to auto). // +optional Ethernet *Ethernet `json:"ethernet,omitempty"` + + // Encapsulation defines the subinterfaces config for an L3 interface. + // +optional + Encapsulation *Encapsulation `json:"encapsulation,omitempty"` + + // ParentInterfaceRef is a reference to the parent interface for this subinterface. + // Required if the interface type is Subinterface. Must not be set for other interface types. + // +optional + ParentInterfaceRef *LocalObjectReference `json:"parentInterfaceRef,omitempty"` } // AdminState represents the administrative state of a resource. @@ -120,7 +132,7 @@ const ( ) // InterfaceType represents the type of the interface. -// +kubebuilder:validation:Enum=Physical;Loopback;Aggregate;RoutedVLAN +// +kubebuilder:validation:Enum=Physical;Loopback;Aggregate;RoutedVLAN;Subinterface type InterfaceType string const ( @@ -132,6 +144,8 @@ const ( InterfaceTypeAggregate InterfaceType = "Aggregate" // InterfaceTypeRoutedVLAN indicates that the interface is a routed VLAN interface (SVI/IRB). InterfaceTypeRoutedVLAN InterfaceType = "RoutedVLAN" + // InterfaceTypeSubinterface indicates that the interface is a subinterface of an interface. + InterfaceTypeSubinterface InterfaceType = "Subinterface" ) // Switchport defines the switchport configuration for an interface. @@ -165,6 +179,44 @@ type Switchport struct { AllowedVlans []int32 `json:"allowedVlans,omitempty"` } +// +kubebuilder:validation:Enum="802.1q";"802.1ad" +type EncapType string + +const ( + // EncapsulationTypeDot1Q indicates IEEE 802.1Q encapsulation. + EncapsulationTypeDot1Q EncapType = "802.1q" + // EncapsulationTypeQinQ indicates IEEE 802.1ad encapsulation. + EncapsulationTypeQinQ EncapType = "802.1ad" +) + +// Encapsulation defines config for an L3 subinterface. +// +kubebuilder:validation:XValidation:rule="self.type != '802.1q' || has(self.tag)", message="tag must be specified for interfaces of type 802.1q" +// +kubebuilder:validation:XValidation:rule="self.type != '802.1q' || !(has(self.innerTag) || has(self.outerTag))", message="innerTag or outerTag must not be specified for interfaces of type 802.1q" +// +kubebuilder:validation:XValidation:rule="self.type != '802.1ad' || (has(self.innerTag) && has(self.outerTag))", message="innerTag and outerTag must be specified for interfaces of type 802.1ad" +// +kubebuilder:validation:XValidation:rule="self.type != '802.1ad' || !has(self.tag)", message="tag must not be specified for interfaces of type 802.1ad" +type Encapsulation struct { + // +required + Type EncapType `json:"type"` + // +optional + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=4094 + Tag int32 `json:"tag"` + + // InnerTag specifies the inner VLAN ID for QinQ encapsulation. + // Only applicable when Type is set to "QinQ". + // +optional + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=4094 + InnerTag int32 `json:"innerTag,omitempty"` + + // OuterTag specifies the outer VLAN ID for QinQ encapsulation. + // Only applicable when Type is set to "QinQ". + // +optional + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=4094 + OuterTag int32 `json:"outerTag,omitempty"` +} + // SwitchportMode represents the switchport mode of an interface. // +kubebuilder:validation:Enum=Access;Trunk type SwitchportMode string diff --git a/api/core/v1alpha1/zz_generated.deepcopy.go b/api/core/v1alpha1/zz_generated.deepcopy.go index e33d64b1b..2995fd795 100644 --- a/api/core/v1alpha1/zz_generated.deepcopy.go +++ b/api/core/v1alpha1/zz_generated.deepcopy.go @@ -1454,6 +1454,21 @@ func (in *EVPNRouteTarget) DeepCopy() *EVPNRouteTarget { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Encapsulation) DeepCopyInto(out *Encapsulation) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Encapsulation. +func (in *Encapsulation) DeepCopy() *Encapsulation { + if in == nil { + return nil + } + out := new(Encapsulation) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Endpoint) DeepCopyInto(out *Endpoint) { *out = *in @@ -1799,6 +1814,16 @@ func (in *InterfaceSpec) DeepCopyInto(out *InterfaceSpec) { *out = new(Ethernet) **out = **in } + if in.Encapsulation != nil { + in, out := &in.Encapsulation, &out.Encapsulation + *out = new(Encapsulation) + **out = **in + } + if in.ParentInterfaceRef != nil { + in, out := &in.ParentInterfaceRef, &out.ParentInterfaceRef + *out = new(LocalObjectReference) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InterfaceSpec. diff --git a/charts/network-operator/templates/crd/interfaces.networking.metal.ironcore.dev.yaml b/charts/network-operator/templates/crd/interfaces.networking.metal.ironcore.dev.yaml index 4fb7fb138..918df2e8d 100644 --- a/charts/network-operator/templates/crd/interfaces.networking.metal.ironcore.dev.yaml +++ b/charts/network-operator/templates/crd/interfaces.networking.metal.ironcore.dev.yaml @@ -217,6 +217,50 @@ spec: x-kubernetes-validations: - message: DeviceRef is immutable rule: self == oldSelf + encapsulation: + description: Encapsulation defines the subinterfaces config for an + L3 interface. + properties: + innerTag: + description: |- + InnerTag specifies the inner VLAN ID for QinQ encapsulation. + Only applicable when Type is set to "QinQ". + format: int32 + maximum: 4094 + minimum: 1 + type: integer + outerTag: + description: |- + OuterTag specifies the outer VLAN ID for QinQ encapsulation. + Only applicable when Type is set to "QinQ". + format: int32 + maximum: 4094 + minimum: 1 + type: integer + tag: + format: int32 + maximum: 4094 + minimum: 1 + type: integer + type: + enum: + - 802.1q + - 802.1ad + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: tag must be specified for interfaces of type 802.1q + rule: self.type != '802.1q' || has(self.tag) + - message: innerTag or outerTag must not be specified for interfaces + of type 802.1q + rule: self.type != '802.1q' || !(has(self.innerTag) || has(self.outerTag)) + - message: innerTag and outerTag must be specified for interfaces + of type 802.1ad + rule: self.type != '802.1ad' || (has(self.innerTag) && has(self.outerTag)) + - message: tag must not be specified for interfaces of type 802.1ad + rule: self.type != '802.1ad' || !has(self.tag) ethernet: description: |- Ethernet defines the ethernet-specific configuration for physical interfaces. @@ -301,6 +345,22 @@ spec: x-kubernetes-validations: - message: Name is immutable rule: self == oldSelf + parentInterfaceRef: + description: |- + ParentInterfaceRef is a reference to the parent interface for this subinterface. + Required if the interface type is Subinterface. Must not be set for other interface types. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + maxLength: 63 + minLength: 1 + type: string + required: + - name + type: object + x-kubernetes-map-type: atomic providerConfigRef: description: |- ProviderConfigRef is a reference to a resource holding the provider-specific configuration of this interface. @@ -388,6 +448,7 @@ spec: - Loopback - Aggregate - RoutedVLAN + - Subinterface type: string x-kubernetes-validations: - message: Type is immutable @@ -466,6 +527,16 @@ spec: - message: bfd must not be specified for Aggregate interfaces with switchport configuration rule: self.type != 'Aggregate' || !has(self.switchport) || !has(self.bfd) + - message: encapsulation and parentInterfaceRef must only be specified + for subinterfaces + rule: self.type == 'Subinterface' || !(has(self.encapsulation) || has(self.parentInterfaceRef)) + - message: subinterface must not have aggregation, switchport or vlanRef + configuration + rule: self.type != 'Subinterface' || !(has(self.aggregation) || has(self.switchport) + || has(self.vlanRef)) + - message: encapsulation and parentInterfaceRef must both be specified + for subinterfaces + rule: self.type != 'Subinterface' || (has(self.encapsulation) && has(self.parentInterfaceRef)) - message: bfd must not be specified for interfaces with switchport configuration rule: '!has(self.bfd) || !has(self.switchport)' - message: ethernet configuration must only be specified on interfaces diff --git a/config/crd/bases/networking.metal.ironcore.dev_interfaces.yaml b/config/crd/bases/networking.metal.ironcore.dev_interfaces.yaml index 1f69cfae5..ab77c10b5 100644 --- a/config/crd/bases/networking.metal.ironcore.dev_interfaces.yaml +++ b/config/crd/bases/networking.metal.ironcore.dev_interfaces.yaml @@ -214,6 +214,50 @@ spec: x-kubernetes-validations: - message: DeviceRef is immutable rule: self == oldSelf + encapsulation: + description: Encapsulation defines the subinterfaces config for an + L3 interface. + properties: + innerTag: + description: |- + InnerTag specifies the inner VLAN ID for QinQ encapsulation. + Only applicable when Type is set to "QinQ". + format: int32 + maximum: 4094 + minimum: 1 + type: integer + outerTag: + description: |- + OuterTag specifies the outer VLAN ID for QinQ encapsulation. + Only applicable when Type is set to "QinQ". + format: int32 + maximum: 4094 + minimum: 1 + type: integer + tag: + format: int32 + maximum: 4094 + minimum: 1 + type: integer + type: + enum: + - 802.1q + - 802.1ad + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: tag must be specified for interfaces of type 802.1q + rule: self.type != '802.1q' || has(self.tag) + - message: innerTag or outerTag must not be specified for interfaces + of type 802.1q + rule: self.type != '802.1q' || !(has(self.innerTag) || has(self.outerTag)) + - message: innerTag and outerTag must be specified for interfaces + of type 802.1ad + rule: self.type != '802.1ad' || (has(self.innerTag) && has(self.outerTag)) + - message: tag must not be specified for interfaces of type 802.1ad + rule: self.type != '802.1ad' || !has(self.tag) ethernet: description: |- Ethernet defines the ethernet-specific configuration for physical interfaces. @@ -298,6 +342,22 @@ spec: x-kubernetes-validations: - message: Name is immutable rule: self == oldSelf + parentInterfaceRef: + description: |- + ParentInterfaceRef is a reference to the parent interface for this subinterface. + Required if the interface type is Subinterface. Must not be set for other interface types. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + maxLength: 63 + minLength: 1 + type: string + required: + - name + type: object + x-kubernetes-map-type: atomic providerConfigRef: description: |- ProviderConfigRef is a reference to a resource holding the provider-specific configuration of this interface. @@ -385,6 +445,7 @@ spec: - Loopback - Aggregate - RoutedVLAN + - Subinterface type: string x-kubernetes-validations: - message: Type is immutable @@ -463,6 +524,16 @@ spec: - message: bfd must not be specified for Aggregate interfaces with switchport configuration rule: self.type != 'Aggregate' || !has(self.switchport) || !has(self.bfd) + - message: encapsulation and parentInterfaceRef must only be specified + for subinterfaces + rule: self.type == 'Subinterface' || !(has(self.encapsulation) || has(self.parentInterfaceRef)) + - message: subinterface must not have aggregation, switchport or vlanRef + configuration + rule: self.type != 'Subinterface' || !(has(self.aggregation) || has(self.switchport) + || has(self.vlanRef)) + - message: encapsulation and parentInterfaceRef must both be specified + for subinterfaces + rule: self.type != 'Subinterface' || (has(self.encapsulation) && has(self.parentInterfaceRef)) - message: bfd must not be specified for interfaces with switchport configuration rule: '!has(self.bfd) || !has(self.switchport)' - message: ethernet configuration must only be specified on interfaces diff --git a/docs/api-reference/index.md b/docs/api-reference/index.md index 2ff55b965..9b0bc3c9c 100644 --- a/docs/api-reference/index.md +++ b/docs/api-reference/index.md @@ -1106,6 +1106,43 @@ _Appears in:_ | `action` _[RouteTargetAction](#routetargetaction)_ | Action defines whether the route target is imported, exported, or both. | | Enum: [Import Export Both]
Required: \{\}
| +#### EncapType + +_Underlying type:_ _string_ + + + +_Validation:_ +- Enum: [802.1q 802.1ad] + +_Appears in:_ +- [Encapsulation](#encapsulation) + +| Field | Description | +| --- | --- | +| `802.1q` | EncapsulationTypeDot1Q indicates IEEE 802.1Q encapsulation.
| +| `802.1ad` | EncapsulationTypeQinQ indicates IEEE 802.1ad encapsulation.
| + + +#### Encapsulation + + + +Encapsulation defines config for an L3 subinterface. + + + +_Appears in:_ +- [InterfaceSpec](#interfacespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `type` _[EncapType](#encaptype)_ | | | Enum: [802.1q 802.1ad]
Required: \{\}
| +| `tag` _integer_ | | | Maximum: 4094
Minimum: 1
Optional: \{\}
| +| `innerTag` _integer_ | InnerTag specifies the inner VLAN ID for QinQ encapsulation.
Only applicable when Type is set to "QinQ". | | Maximum: 4094
Minimum: 1
Optional: \{\}
| +| `outerTag` _integer_ | OuterTag specifies the outer VLAN ID for QinQ encapsulation.
Only applicable when Type is set to "QinQ". | | Maximum: 4094
Minimum: 1
Optional: \{\}
| + + #### Endpoint @@ -1403,7 +1440,7 @@ _Appears in:_ | `name` _string_ | Name is the name of the interface. | | MaxLength: 255
MinLength: 1
Required: \{\}
| | `adminState` _[AdminState](#adminstate)_ | AdminState indicates whether the interface is administratively up or down. | Up | Enum: [Up Down]
Optional: \{\}
| | `description` _string_ | Description provides a human-readable description of the interface. | | MaxLength: 255
Optional: \{\}
| -| `type` _[InterfaceType](#interfacetype)_ | Type indicates the type of the interface. | | Enum: [Physical Loopback Aggregate RoutedVLAN]
Required: \{\}
| +| `type` _[InterfaceType](#interfacetype)_ | Type indicates the type of the interface. | | Enum: [Physical Loopback Aggregate RoutedVLAN Subinterface]
Required: \{\}
| | `mtu` _integer_ | MTU (Maximum Transmission Unit) specifies the size of the largest packet that can be sent over the interface. | | Maximum: 9216
Minimum: 576
Optional: \{\}
| | `switchport` _[Switchport](#switchport)_ | Switchport defines the switchport configuration for the interface.
This is only applicable for Ethernet and Aggregate interfaces. | | Optional: \{\}
| | `ipv4` _[InterfaceIPv4](#interfaceipv4)_ | IPv4 defines the IPv4 configuration for the interface. | | Optional: \{\}
| @@ -1412,6 +1449,8 @@ _Appears in:_ | `vrfRef` _[LocalObjectReference](#localobjectreference)_ | VrfRef is a reference to the VRF resource that this interface belongs to.
If not specified, the interface will be part of the default VRF.
This is only applicable for Layer 3 interfaces.
The referenced VRF must exist in the same namespace. | | Optional: \{\}
| | `bfd` _[BFD](#bfd)_ | BFD defines the Bidirectional Forwarding Detection configuration for the interface.
BFD is only applicable for Layer 3 interfaces. | | Optional: \{\}
| | `ethernet` _[Ethernet](#ethernet)_ | Ethernet defines the ethernet-specific configuration for physical interfaces.
This configuration is only applicable to Physical interfaces.
When omitted, ethernet parameters use their default values (e.g., FEC mode defaults to auto). | | Optional: \{\}
| +| `encapsulation` _[Encapsulation](#encapsulation)_ | Encapsulation defines the subinterfaces config for an L3 interface. | | Optional: \{\}
| +| `parentInterfaceRef` _[LocalObjectReference](#localobjectreference)_ | ParentInterfaceRef is a reference to the parent interface for this subinterface.
Required if the interface type is Subinterface. Must not be set for other interface types. | | Optional: \{\}
| #### InterfaceStatus @@ -1438,7 +1477,7 @@ _Underlying type:_ _string_ InterfaceType represents the type of the interface. _Validation:_ -- Enum: [Physical Loopback Aggregate RoutedVLAN] +- Enum: [Physical Loopback Aggregate RoutedVLAN Subinterface] _Appears in:_ - [InterfaceSpec](#interfacespec) @@ -1449,6 +1488,7 @@ _Appears in:_ | `Loopback` | InterfaceTypeLoopback indicates that the interface is a loopback interface.
| | `Aggregate` | InterfaceTypeAggregate indicates that the interface is an aggregate (bundle) interface.
| | `RoutedVLAN` | InterfaceTypeRoutedVLAN indicates that the interface is a routed VLAN interface (SVI/IRB).
| +| `Subinterface` | InterfaceTypeSubinterface indicates that the interface is a subinterface of an interface.
| #### LACPMode