Skip to content

Commit 58bc153

Browse files
Add RoutingPolicy resource and controller
1 parent 66d719e commit 58bc153

24 files changed

+2146
-30
lines changed

PROJECT

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,4 +198,12 @@ resources:
198198
webhooks:
199199
validation: true
200200
webhookVersion: v1
201+
- api:
202+
crdVersion: v1
203+
namespaced: true
204+
controller: true
205+
domain: networking.metal.ironcore.dev
206+
kind: RoutingPolicy
207+
path: github.com/ironcore-dev/network-operator/api/core/v1alpha1
208+
version: v1alpha1
201209
version: "3"

Tiltfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ k8s_resource(new_name='vxlan-100010', objects=['vxlan-100010:evpninstance'], res
108108
k8s_yaml('./config/samples/v1alpha1_prefixset.yaml')
109109
k8s_resource(new_name='ccloud-prefixset', objects=['ccloud-prefixset:prefixset'], trigger_mode=TRIGGER_MODE_MANUAL, auto_init=False)
110110

111+
k8s_yaml('./config/samples/v1alpha1_routingpolicy.yaml')
112+
k8s_resource(new_name='bgp-import-policy', objects=['bgp-import-policy:routingpolicy', 'internal-networks:prefixset', 'partner-networks:prefixset', 'blocked-networks:prefixset'], trigger_mode=TRIGGER_MODE_MANUAL, auto_init=False)
113+
111114
print('🚀 network-operator development environment')
112115
print('👉 Edit the code inside the api/, cmd/, or internal/ directories')
113116
print('👉 Tilt will automatically rebuild and redeploy when changes are detected')

api/core/v1alpha1/groupversion_info.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,9 @@ const (
134134
// VRFNotFoundReason indicates that a referenced VRF was not found.
135135
VRFNotFoundReason = "VRFNotFound"
136136
)
137+
138+
// Reasons that are specific to [RoutingPolicy] objects.
139+
const (
140+
// PrefixSetNotFoundReason indicates that a referenced PrefixSet was not found.
141+
PrefixSetNotFoundReason = "PrefixSetNotFound"
142+
)
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package v1alpha1
5+
6+
import (
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
)
9+
10+
// RoutingPolicySpec defines the desired state of RoutingPolicy
11+
type RoutingPolicySpec struct {
12+
// DeviceName is the name of the Device this object belongs to. The Device object must exist in the same namespace.
13+
// Immutable.
14+
// +required
15+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="DeviceRef is immutable"
16+
DeviceRef LocalObjectReference `json:"deviceRef"`
17+
18+
// ProviderConfigRef is a reference to a resource holding the provider-specific configuration of this interface.
19+
// This reference is used to link the Banner to its provider-specific configuration.
20+
// +optional
21+
ProviderConfigRef *TypedLocalObjectReference `json:"providerConfigRef,omitempty"`
22+
23+
// Name is the identifier of the RoutingPolicy on the device.
24+
// Immutable.
25+
// +required
26+
// +kubebuilder:validation:MinLength=1
27+
// +kubebuilder:validation:MaxLength=63
28+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Name is immutable"
29+
Name string `json:"name"`
30+
31+
// A list of policy statements to apply.
32+
// +required
33+
// +listType=map
34+
// +listMapKey=sequence
35+
// +kubebuilder:validation:MinItems=1
36+
// +kubebuilder:validation:MaxItems=100
37+
Statements []PolicyStatement `json:"statements"`
38+
}
39+
40+
type PolicyStatement struct {
41+
// The sequence number of the policy statement.
42+
// +required
43+
// +kubebuilder:validation:Minimum=1
44+
Sequence int32 `json:"sequence"`
45+
46+
// Conditions define the match criteria for this statement.
47+
// If no conditions are specified, the statement matches all routes.
48+
// +optional
49+
Conditions *PolicyConditions `json:"conditions,omitempty"`
50+
51+
// Actions define what to do when conditions match.
52+
// +required
53+
Actions PolicyActions `json:"actions"`
54+
}
55+
56+
// PolicyConditions defines the match criteria for a policy statement.
57+
type PolicyConditions struct {
58+
// MatchPrefixSet matches routes against a PrefixSet resource.
59+
// +optional
60+
MatchPrefixSet *PrefixSetMatchCondition `json:"matchPrefixSet,omitempty"`
61+
}
62+
63+
// PrefixSetMatchCondition defines the condition for matching against a PrefixSet.
64+
type PrefixSetMatchCondition struct {
65+
// PrefixSetRef references a PrefixSet in the same namespace.
66+
// The PrefixSet must exist and belong to the same device.
67+
// +required
68+
PrefixSetRef LocalObjectReference `json:"prefixSetRef"`
69+
}
70+
71+
// PolicyActions defines the actions to take when a policy statement matches.
72+
// +kubebuilder:validation:XValidation:rule="self.routeDisposition == 'AcceptRoute' || !has(self.bgpActions)",message="bgpActions cannot be specified when routeDisposition is RejectRoute"
73+
type PolicyActions struct {
74+
// RouteDisposition specifies whether to accept or reject the route.
75+
// +required
76+
RouteDisposition RouteDisposition `json:"routeDisposition"`
77+
78+
// BgpActions specifies BGP-specific actions to apply when the route is accepted.
79+
// Only applicable when RouteDisposition is AcceptRoute.
80+
// +optional
81+
BgpActions *BgpActions `json:"bgpActions,omitempty"`
82+
}
83+
84+
// RouteDisposition defines the final disposition of a route.
85+
// +kubebuilder:validation:Enum=AcceptRoute;RejectRoute
86+
type RouteDisposition string
87+
88+
const (
89+
// AcceptRoute permits the route and applies any configured actions.
90+
AcceptRoute RouteDisposition = "AcceptRoute"
91+
// RejectRoute denies the route immediately.
92+
RejectRoute RouteDisposition = "RejectRoute"
93+
)
94+
95+
// BgpActions defines BGP-specific actions for a policy statement.
96+
// +kubebuilder:validation:XValidation:rule="has(self.setCommunity) || has(self.setExtCommunity)",message="at least one BGP action must be specified"
97+
type BgpActions struct {
98+
// SetCommunity configures BGP standard community attributes.
99+
// +optional
100+
SetCommunity *SetCommunityAction `json:"setCommunity,omitempty"`
101+
102+
// SetExtCommunity configures BGP extended community attributes.
103+
// +optional
104+
SetExtCommunity *SetExtCommunityAction `json:"setExtCommunity,omitempty"`
105+
}
106+
107+
// SetCommunityAction defines the action to set BGP standard communities.
108+
type SetCommunityAction struct {
109+
// Communities is the list of BGP standard communities to set.
110+
// The communities must be in the format defined by [RFC 1997].
111+
// [RFC 1997]: https://datatracker.ietf.org/doc/html/rfc1997
112+
// +required
113+
// +kubebuilder:validation:MinItems=1
114+
Communities []string `json:"communities"`
115+
}
116+
117+
// SetExtCommunityAction defines the action to set BGP extended communities.
118+
type SetExtCommunityAction struct {
119+
// Communities is the list of BGP extended communities to set.
120+
// The communities must be in the format defined by [RFC 4360].
121+
// [RFC 4360]: https://datatracker.ietf.org/doc/html/rfc4360
122+
// +required
123+
// +kubebuilder:validation:MinItems=1
124+
Communities []string `json:"communities"`
125+
}
126+
127+
// RoutingPolicyStatus defines the observed state of RoutingPolicy.
128+
type RoutingPolicyStatus struct {
129+
// The conditions are a list of status objects that describe the state of the RoutingPolicy.
130+
//+listType=map
131+
//+listMapKey=type
132+
//+patchStrategy=merge
133+
//+patchMergeKey=type
134+
//+optional
135+
Conditions []metav1.Condition `json:"conditions,omitempty"`
136+
}
137+
138+
// +kubebuilder:object:root=true
139+
// +kubebuilder:subresource:status
140+
// +kubebuilder:resource:path=routingpolicies
141+
// +kubebuilder:resource:singular=routingpolicy
142+
// +kubebuilder:resource:shortName=routemap
143+
// +kubebuilder:printcolumn:name="Routing Policy",type=string,JSONPath=`.spec.name`
144+
// +kubebuilder:printcolumn:name="Device",type=string,JSONPath=`.spec.deviceRef.name`
145+
// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`
146+
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
147+
148+
// RoutingPolicy is the Schema for the routingpolicies API
149+
type RoutingPolicy struct {
150+
metav1.TypeMeta `json:",inline"`
151+
metav1.ObjectMeta `json:"metadata,omitempty"`
152+
153+
// Specification of the desired state of the resource.
154+
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
155+
// +required
156+
Spec RoutingPolicySpec `json:"spec,omitempty"`
157+
158+
// Status of the resource. This is set and updated automatically.
159+
// Read-only.
160+
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
161+
// +optional
162+
Status RoutingPolicyStatus `json:"status,omitempty,omitzero"`
163+
}
164+
165+
// GetConditions implements conditions.Getter.
166+
func (p *RoutingPolicy) GetConditions() []metav1.Condition {
167+
return p.Status.Conditions
168+
}
169+
170+
// SetConditions implements conditions.Setter.
171+
func (p *RoutingPolicy) SetConditions(conditions []metav1.Condition) {
172+
p.Status.Conditions = conditions
173+
}
174+
175+
// +kubebuilder:object:root=true
176+
177+
// RoutingPolicyList contains a list of RoutingPolicy
178+
type RoutingPolicyList struct {
179+
metav1.TypeMeta `json:",inline"`
180+
metav1.ListMeta `json:"metadata,omitzero"`
181+
Items []RoutingPolicy `json:"items"`
182+
}
183+
184+
func init() {
185+
SchemeBuilder.Register(&RoutingPolicy{}, &RoutingPolicyList{})
186+
}

0 commit comments

Comments
 (0)