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