Skip to content
Draft
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 @@ -290,6 +290,14 @@ resources:
kind: DHCPRelay
path: github.com/ironcore-dev/network-operator/api/core/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
domain: networking.metal.ironcore.dev
group: core
kind: StaticRoute
path: github.com/ironcore-dev/network-operator/api/core/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
Expand Down
13 changes: 13 additions & 0 deletions api/core/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ const L2VNILabel = "networking.metal.ironcore.dev/evi-name"
// the name of the VRF they belong to.
const VRFLabel = "networking.metal.ironcore.dev/vrf-name"

// StaticRouteLabel is a label applied to VRFs to indicate
// the name of the StaticRoute that references them.
const StaticRouteLabel = "networking.metal.ironcore.dev/static-route-name"

// DeviceMaintenanceAnnotation is an annotation that can be applied to Device objects
// to trigger certain disruptive operations, such as reboots or firmware upgrades.
const DeviceMaintenanceAnnotation = "networking.metal.ironcore.dev/maintenance"
Expand Down Expand Up @@ -217,6 +221,15 @@ const (
// VRFNotFoundReason indicates that a referenced VRF was not found.
VRFNotFoundReason = "VRFNotFound"

// VRFNotConfiguredReason indicates that a referenced VRF is not configured.
VRFNotConfiguredReason = "VRFNotConfigured"

// VRFAlreadyInUseReason indicates that a referenced VRF is already in use by another interface or static route.
VRFAlreadyInUseReason = "VRFAlreadyInUse"

// InterfaceNotConfiguredReason indicates that a referenced interface is not configured.
InterfaceNotConfiguredReason = "InterfaceNotConfigured"

// ParentInterfaceNotFoundReason indicates that a referenced parent interface for a subinterface was not found.
ParentInterfaceNotFoundReason = "ParentInterfaceNotFound"

Expand Down
145 changes: 145 additions & 0 deletions api/core/v1alpha1/staticroute_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-License-Identifier: Apache-2.0

package v1alpha1

import (
"sync"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)

// StaticRouteSpec defines the desired state of StaticRoute
// Static routes are used to define explicit paths for network traffic. They can be categorized into different types based on their characteristics and use cases:
// Directly Connected Routes: Only output interfaces are specified, and the next hop is directly reachable through those interfaces.
// Recursive Static Routes: In a recursive static route, only the next hop is specified. The output interface is derived from the next hop.
// Fully Specified Static Routes: Specifies both the output interfaces and the next hop, providing a complete path for the traffic.
// Floating Static Routes: These routes have a higher administrative distance than dynamic routes, allowing them to serve as backup routes that are only used when the primary route is unavailable.
type StaticRouteSpec 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 Interface to its provider-specific configuration.
// +optional
ProviderConfigRef *TypedLocalObjectReference `json:"providerConfigRef,omitempty"`

// Name is the name of the static route.
// +required
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=255
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Name is immutable"
Name string `json:"name"`

// +optional
// +kubebuilder:validation:MaxLength=255
Description string `json:"description,omitempty"`

// VrfRef is a reference to the VRF resource that this static route belongs to.
// If not specified, the static route will be part of the default VRF.
// The referenced VRF must exist in the same namespace.
// +optional
VrfRef *LocalObjectReference `json:"vrfRef,omitempty"`

// +required
// +kubebuilder:validation:MinItems=1
Routes []StaticRoutes `json:"routes,omitempty"`
}

type StaticRoutes struct {
// TODO(sven-rosenzweig): It is possible to point an a static route in a VRF to an Interface. For now this is not needed.
// InterfaceRef is a reference to the Interface resource that this static route is associated with.
// The referenced Interface must exist in the same namespace.
// +optional
// InterfaceRef *LocalObjectReference `json:"interfaceRef,omitempty"`

// IPPrefix is the destination IP prefix for the static route.
// +required
IPPrefix IPPrefix `json:"ipPrefix"`

// NextHop is the IP address of the next hop for the static route.
// +optional
NextHop string `json:"nextHop"`

// AdministrativeDistance assigns a priority to the static route. Lower values indicate higher priority.
// +optional
AdministrativeDistance *int32 `json:"administrativeDistance,omitempty"`
}

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

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name`
// +kubebuilder:printcolumn:name="VRF",type=string,JSONPath=`.spec.vrfRef.name`
// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`
// +kubebuilder:printcolumn:name="Paused",type=string,JSONPath=`.status.conditions[?(@.type=="Paused")].status`,priority=1
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"

// StaticRoute is the Schema for the staticroutes API
type StaticRoute struct {
metav1.TypeMeta `json:",inline"`

// metadata is a standard object metadata
// +optional
metav1.ObjectMeta `json:"metadata,omitzero"`

// spec defines the desired state of StaticRoute
// +required
Spec StaticRouteSpec `json:"spec"`

// status defines the observed state of StaticRoute
// +optional
Status StaticRouteStatus `json:"status,omitzero"`
}

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

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

// +kubebuilder:object:root=true

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

var (
StaticRouteDependencies []schema.GroupVersionKind
staticRouteDependenciesMu sync.Mutex
)

func RegisterStaticRouteDependency(gvk schema.GroupVersionKind) {
staticRouteDependenciesMu.Lock()
defer staticRouteDependenciesMu.Unlock()
StaticRouteDependencies = append(StaticRouteDependencies, gvk)
}

func init() {
SchemeBuilder.Register(func(s *runtime.Scheme) error {
s.AddKnownTypes(GroupVersion, &StaticRoute{}, &StaticRouteList{})
return nil
})
}
135 changes: 135 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.

3 changes: 3 additions & 0 deletions charts/network-operator/templates/rbac/manager-role.yaml

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

13 changes: 13 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,19 @@ func main() { //nolint:gocyclo
os.Exit(1)
}

if err := (&corecontroller.StaticRouteReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorder("staticroute-controller"),
WatchFilterValue: watchFilterValue,
Provider: prov,
Locker: locker,
RequeueInterval: requeueInterval,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "StaticRoute")
os.Exit(1)
}

if os.Getenv("ENABLE_WEBHOOKS") != "false" {
if err := webhookv1alpha1.SetupVRFWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "VRF")
Expand Down
Loading
Loading