Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,12 @@ resources:
kind: VLAN
path: github.com/ironcore-dev/network-operator/api/core/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: networking.metal.ironcore.dev
kind: EVPNInstance
path: github.com/ironcore-dev/network-operator/api/core/v1alpha1
version: v1alpha1
version: "3"
3 changes: 3 additions & 0 deletions Tiltfile
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ k8s_resource(new_name='ospf-underlay', objects=['underlay:ospf'], resource_deps=
k8s_yaml('./config/samples/v1alpha1_vlan.yaml')
k8s_resource(new_name='vlan-10', objects=['vlan-10:vlan'], trigger_mode=TRIGGER_MODE_MANUAL, auto_init=False)

k8s_yaml('./config/samples/v1alpha1_evi.yaml')
k8s_resource(new_name='vxlan-100010', objects=['vxlan-100010:evpninstance'], resource_deps=['vlan-10'], trigger_mode=TRIGGER_MODE_MANUAL, auto_init=False)

print('🚀 network-operator development environment')
print('👉 Edit the code inside the api/, cmd/, or internal/ directories')
print('👉 Tilt will automatically rebuild and redeploy when changes are detected')
Expand Down
157 changes: 157 additions & 0 deletions api/core/v1alpha1/evpninstance_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// SPDX-FileCopyrightText: 2025 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"
)

// EVPNInstanceSpec defines the desired state of EVPNInstance
//
// It models an EVPN instance (EVI) context on a single network device based on VXLAN encapsulation and the VLAN-based service type defined in [RFC 8365].
// [RFC 8365]: https://datatracker.ietf.org/doc/html/rfc8365
//
// +kubebuilder:validation:XValidation:rule="self.type != 'Bridged' || has(self.vlanRef)",message="VLANRef must be specified when Type is Bridged"
type EVPNInstanceSpec struct {
// DeviceName is the name of the Device this object belongs to. The Device object must exist in the same namespace.
// Immutable.
// +required
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="DeviceRef is immutable"
DeviceRef LocalObjectReference `json:"deviceRef"`

// ProviderConfigRef is a reference to a resource holding the provider-specific configuration of this interface.
// This reference is used to link the BGP to its provider-specific configuration.
// +optional
ProviderConfigRef *TypedLocalObjectReference `json:"providerConfigRef,omitempty"`

// VNI is the VXLAN Network Identifier.
// Immutable.
// +required
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=16777214
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="VNI is immutable"
VNI int32 `json:"vni"`

// Type specifies the EVPN instance type.
// Immutable.
// +required
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Type is immutable"
Type EVPNInstanceType `json:"type"`

// MulticastGroupAddress specifies the IPv4 multicast group address used for BUM (Broadcast, Unknown unicast, Multicast) traffic.
// The address must be in the valid multicast range (224.0.0.0 - 239.255.255.255).
// +optional
// +kubebuilder:validation:Format=ipv4
MulticastGroupAddress string `json:"multicastGroupAddress,omitempty"`

// RouteDistinguisher is the route distinguisher for the EVI.
// Formats supported:
// - Type 0: <asn(0-65535)>:<number(0-4294967295)>
// - Type 1: <ipv4>:<number(0-65535)>
// - Type 2: <asn(65536-4294967295)>:<number(0-65535)>
// +optional
RouteDistinguisher string `json:"routeDistinguisher,omitempty"`

// RouteTargets is the list of route targets for the EVI.
// +optional
// +listType=map
// +listMapKey=value
// +kubebuilder:validation:MinItems=1
RouteTargets []EVPNRouteTarget `json:"routeTargets,omitempty"`

// 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
// +kubebuilder:validation:XValidation:rule="self.name == oldSelf.name",message="VLANRef is immutable"
VLANRef *LocalObjectReference `json:"vlanRef,omitempty"`
}

// EVPNInstanceType defines the type of EVPN instance.
// +kubebuilder:validation:Enum=Bridged;Routed
type EVPNInstanceType string

const (
// EVPNInstanceTypeBridged represents an L2VNI (MAC-VRF) EVPN instance.
// Corresponds to OpenConfig network-instance type L2VSI.
EVPNInstanceTypeBridged EVPNInstanceType = "Bridged"

// EVPNInstanceTypeRouted represents an L3VNI (IP-VRF) EVPN instance.
// Corresponds to OpenConfig network-instance type L3VRF.
EVPNInstanceTypeRouted EVPNInstanceType = "Routed"
)

type EVPNRouteTarget struct {
// Value is the route target value, must have the format as RouteDistinguisher.
// +required
// +kubebuilder:validation:MinLength=1
Value string `json:"value"`

// Action defines whether the route target is imported, exported, or both.
// +required
Action RouteTargetAction `json:"action"`
}

// EVPNInstanceStatus defines the observed state of EVPNInstance.
type EVPNInstanceStatus struct {
// The conditions are a list of status objects that describe the state of the EVPNInstance.
// +listType=map
// +listMapKey=type
// +patchStrategy=merge
// +patchMergeKey=type
// +optional
Conditions []metav1.Condition `json:"conditions,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:path=evpninstances
// +kubebuilder:resource:singular=evpninstance
// +kubebuilder:resource:shortName=evi;vni
// +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name`
// +kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.spec.type`
// +kubebuilder:printcolumn:name="VNI",type=integer,JSONPath=`.spec.vni`
// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"

// EVPNInstance is the Schema for the evpninstances API
type EVPNInstance struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

// Specification of the desired state of the resource.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
// +required
Spec EVPNInstanceSpec `json:"spec"`

// Status of the resource. This is set and updated automatically.
// Read-only.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
// +optional
Status EVPNInstanceStatus `json:"status,omitempty,omitzero"`
}

// GetConditions implements conditions.Getter.
func (i *EVPNInstance) GetConditions() []metav1.Condition {
return i.Status.Conditions
}

// SetConditions implements conditions.Setter.
func (i *EVPNInstance) SetConditions(conditions []metav1.Condition) {
i.Status.Conditions = conditions
}

// +kubebuilder:object:root=true

// EVPNInstanceList contains a list of EVPNInstance
type EVPNInstanceList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []EVPNInstance `json:"items"`
}

func init() {
SchemeBuilder.Register(&EVPNInstance{}, &EVPNInstanceList{})
}
4 changes: 4 additions & 0 deletions api/core/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ const AggregateLabel = "networking.metal.ironcore.dev/aggregate-name"
// the name of the RoutedVLAN interface that provides Layer 3 routing for the VLAN.
const RoutedVLANLabel = "networking.metal.ironcore.dev/routed-vlan-name"

// L2VNILabel is a label applied to VLANs to indicate
// the name of the EVPNInstance that maps the VLAN to a L2VNI in the VXLAN fabric.
const L2VNILabel = "networking.metal.ironcore.dev/evi-name"

// VRFLabel is a label applied to interfaces to indicate
// the name of the VRF they belong to.
const VRFLabel = "networking.metal.ironcore.dev/vrf-name"
Expand Down
5 changes: 5 additions & 0 deletions api/core/v1alpha1/vlan_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ type VLANStatus struct {
// This field is set when an Interface of type RoutedVLAN references this VLAN.
// +optional
RoutedBy *LocalObjectReference `json:"routedBy,omitempty"`

// BridgedBy references the EVPNInstance that provides a L2VNI for this VLAN, if any.
// This field is set when an EVPNInstance of type Bridged references this VLAN.
// +optional
BridgedBy *LocalObjectReference `json:"bridgedBy,omitempty"`
}

// +kubebuilder:object:root=true
Expand Down
132 changes: 132 additions & 0 deletions api/core/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading