Skip to content

Commit 631c4be

Browse files
Add AS-path set actions to RoutingPolicy CRD
Extend the RoutingPolicy API with a new SetASPath action under BgpActions, supporting prepend, prepend last-as repeat-n, replace, and explicit AS-path operations. The API uses vendor-agnostic types with intstr.IntOrString for AS numbers (plain and dotted notation per RFC 5396) and CEL validation rules for mutual exclusivity. While this API is not fully supported in openconfig, which only seems to model the set-as-path-prepend options currently, it seems to be supported on multiple vendors, including Cisco NX-OS[^1] and Nokia SR Linux[^2]. As such it qualifies for being added to the core CRDs as it can be supported across different vendors. [^1]: https://www.cisco.com/c/en/us/td/docs/dcn/nx-os/nexus9000/106x/configuration/unicast-routing-configuration/cisco-nexus-9000-series-nx-os-unicast-routing-configuration-guide/m_configuring_route_policy_manager.html [^2]: https://documentation.nokia.com/srlinux/25-7/books/data-model-reference/srl_nokia-routing-policy_0.html
1 parent 229cadc commit 631c4be

24 files changed

Lines changed: 1138 additions & 1 deletion

PROJECT

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ resources:
214214
kind: RoutingPolicy
215215
path: github.com/ironcore-dev/network-operator/api/core/v1alpha1
216216
version: v1alpha1
217+
webhooks:
218+
validation: true
219+
webhookVersion: v1
217220
- api:
218221
crdVersion: v1
219222
namespaced: true

api/core/v1alpha1/routingpolicy_types.go

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1010
"k8s.io/apimachinery/pkg/runtime/schema"
11+
"k8s.io/apimachinery/pkg/util/intstr"
1112
)
1213

1314
// RoutingPolicySpec defines the desired state of RoutingPolicy
@@ -96,7 +97,7 @@ const (
9697
)
9798

9899
// BgpActions defines BGP-specific actions for a policy statement.
99-
// +kubebuilder:validation:XValidation:rule="has(self.setCommunity) || has(self.setExtCommunity)",message="at least one BGP action must be specified"
100+
// +kubebuilder:validation:XValidation:rule="has(self.setCommunity) || has(self.setExtCommunity) || has(self.setASPath)",message="at least one BGP action must be specified"
100101
type BgpActions struct {
101102
// SetCommunity configures BGP standard community attributes.
102103
// +optional
@@ -105,6 +106,62 @@ type BgpActions struct {
105106
// SetExtCommunity configures BGP extended community attributes.
106107
// +optional
107108
SetExtCommunity *SetExtCommunityAction `json:"setExtCommunity,omitempty"`
109+
110+
// SetASPath configures modifications to the BGP AS path attribute.
111+
// +optional
112+
SetASPath *SetASPathAction `json:"setASPath,omitempty"`
113+
}
114+
115+
// SetASPathAction defines actions to modify the BGP AS path attribute.
116+
// +kubebuilder:validation:XValidation:rule="has(self.prepend) || has(self.replace) || has(self.asNumber)",message="at least one AS path action must be specified"
117+
type SetASPathAction struct {
118+
// Prepend configures prepending to the AS path.
119+
// +optional
120+
Prepend *SetASPathPrepend `json:"prepend,omitempty"`
121+
122+
// Replace configures replacement of AS numbers in the AS path.
123+
// +optional
124+
Replace *SetASPathReplace `json:"replace,omitempty"`
125+
126+
// ASNumber sets the AS path to the specified AS number.
127+
// Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
128+
// +optional
129+
ASNumber *intstr.IntOrString `json:"asNumber,omitempty"`
130+
}
131+
132+
// SetASPathPrepend configures prepending to the BGP AS path.
133+
// Either asNumber or useLastAS must be specified, but not both.
134+
// +kubebuilder:validation:XValidation:rule="has(self.asNumber) != has(self.useLastAS)",message="exactly one of asNumber or useLastAS must be specified"
135+
type SetASPathPrepend struct {
136+
// ASNumber is the autonomous system number to prepend to the AS path.
137+
// Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
138+
// +optional
139+
ASNumber *intstr.IntOrString `json:"asNumber,omitempty"`
140+
141+
// UseLastAS prepends the last AS number in the existing AS path the specified number of times.
142+
// +optional
143+
// +kubebuilder:validation:Minimum=1
144+
// +kubebuilder:validation:Maximum=10
145+
UseLastAS *int32 `json:"useLastAS,omitempty"`
146+
}
147+
148+
// SetASPathReplace configures replacement of AS numbers in the BGP AS path.
149+
// Either privateAS or asNumber must be specified, but not both.
150+
// +kubebuilder:validation:XValidation:rule="has(self.privateAS) != has(self.asNumber)",message="exactly one of privateAS or asNumber must be specified"
151+
type SetASPathReplace struct {
152+
// PrivateAS, when set to true, targets all private AS numbers in the path for replacement.
153+
// +optional
154+
PrivateAS bool `json:"privateAS,omitempty"`
155+
156+
// ASNumber targets a specific AS number in the path for replacement.
157+
// Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
158+
// +optional
159+
ASNumber *intstr.IntOrString `json:"asNumber,omitempty"`
160+
161+
// Replacement is the AS number to substitute in place of matched AS numbers.
162+
// Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
163+
// +required
164+
Replacement intstr.IntOrString `json:"replacement"`
108165
}
109166

110167
// SetCommunityAction defines the action to set BGP standard communities.

api/core/v1alpha1/zz_generated.deepcopy.go

Lines changed: 82 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

charts/network-operator/templates/crd/routingpolicies.networking.metal.ironcore.dev.yaml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,82 @@ spec:
142142
BgpActions specifies BGP-specific actions to apply when the route is accepted.
143143
Only applicable when RouteDisposition is AcceptRoute.
144144
properties:
145+
setASPath:
146+
description: |-
147+
SetASPath configures modifications to the BGP AS path attribute.
148+
Not all providers may support this action.
149+
properties:
150+
asNumber:
151+
anyOf:
152+
- type: integer
153+
- type: string
154+
description: |-
155+
ASNumber sets the AS path to the specified AS number.
156+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
157+
x-kubernetes-int-or-string: true
158+
prepend:
159+
description: Prepend configures prepending to the
160+
AS path.
161+
properties:
162+
asNumber:
163+
anyOf:
164+
- type: integer
165+
- type: string
166+
description: |-
167+
ASNumber is the autonomous system number to prepend to the AS path.
168+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
169+
Mutually exclusive with useLastAS.
170+
x-kubernetes-int-or-string: true
171+
useLastAS:
172+
description: |-
173+
UseLastAS prepends the last AS number in the existing AS path the specified number of times.
174+
Mutually exclusive with asNumber.
175+
format: int32
176+
maximum: 10
177+
minimum: 1
178+
type: integer
179+
type: object
180+
x-kubernetes-validations:
181+
- message: exactly one of asNumber or useLastAS
182+
must be specified
183+
rule: has(self.asNumber) != has(self.useLastAS)
184+
replace:
185+
description: Replace configures replacement of AS
186+
numbers in the AS path.
187+
properties:
188+
asNumber:
189+
anyOf:
190+
- type: integer
191+
- type: string
192+
description: |-
193+
ASNumber targets a specific AS number in the path for replacement.
194+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
195+
Mutually exclusive with privateAS.
196+
x-kubernetes-int-or-string: true
197+
privateAS:
198+
description: |-
199+
PrivateAS, when set to true, targets all private AS numbers in the path for replacement.
200+
Mutually exclusive with asNumber.
201+
type: boolean
202+
replacement:
203+
anyOf:
204+
- type: integer
205+
- type: string
206+
description: |-
207+
Replacement is the AS number to substitute in place of matched AS numbers.
208+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
209+
x-kubernetes-int-or-string: true
210+
required:
211+
- replacement
212+
type: object
213+
x-kubernetes-validations:
214+
- message: exactly one of privateAS or asNumber
215+
must be specified
216+
rule: has(self.privateAS) != has(self.asNumber)
217+
type: object
218+
x-kubernetes-validations:
219+
- message: at least one AS path action must be specified
220+
rule: has(self.prepend) || has(self.replace) || has(self.asNumber)
145221
setCommunity:
146222
description: SetCommunity configures BGP standard community
147223
attributes.
@@ -178,6 +254,7 @@ spec:
178254
x-kubernetes-validations:
179255
- message: at least one BGP action must be specified
180256
rule: has(self.setCommunity) || has(self.setExtCommunity)
257+
|| has(self.setASPath)
181258
routeDisposition:
182259
description: RouteDisposition specifies whether to accept
183260
or reject the route.

cmd/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,11 @@ func main() {
627627
os.Exit(1)
628628
}
629629

630+
if err := webhookv1alpha1.SetupRoutingPolicyWebhookWithManager(mgr); err != nil {
631+
setupLog.Error(err, "Failed to create webhook", "webhook", "RoutingPolicy")
632+
os.Exit(1)
633+
}
634+
630635
if err := webhooknxv1alpha1.SetupNetworkVirtualizationEdgeConfigWebhookWithManager(mgr); err != nil {
631636
setupLog.Error(err, "unable to create webhook", "webhook", "NetworkVirtualizationEdgeConfig")
632637
os.Exit(1)

config/crd/bases/networking.metal.ironcore.dev_routingpolicies.yaml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,78 @@ spec:
139139
BgpActions specifies BGP-specific actions to apply when the route is accepted.
140140
Only applicable when RouteDisposition is AcceptRoute.
141141
properties:
142+
setASPath:
143+
description: SetASPath configures modifications to the
144+
BGP AS path attribute.
145+
properties:
146+
asNumber:
147+
anyOf:
148+
- type: integer
149+
- type: string
150+
description: |-
151+
ASNumber sets the AS path to the specified AS number.
152+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
153+
x-kubernetes-int-or-string: true
154+
prepend:
155+
description: Prepend configures prepending to the
156+
AS path.
157+
properties:
158+
asNumber:
159+
anyOf:
160+
- type: integer
161+
- type: string
162+
description: |-
163+
ASNumber is the autonomous system number to prepend to the AS path.
164+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
165+
x-kubernetes-int-or-string: true
166+
useLastAS:
167+
description: UseLastAS prepends the last AS
168+
number in the existing AS path the specified
169+
number of times.
170+
format: int32
171+
maximum: 10
172+
minimum: 1
173+
type: integer
174+
type: object
175+
x-kubernetes-validations:
176+
- message: exactly one of asNumber or useLastAS
177+
must be specified
178+
rule: has(self.asNumber) != has(self.useLastAS)
179+
replace:
180+
description: Replace configures replacement of AS
181+
numbers in the AS path.
182+
properties:
183+
asNumber:
184+
anyOf:
185+
- type: integer
186+
- type: string
187+
description: |-
188+
ASNumber targets a specific AS number in the path for replacement.
189+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
190+
x-kubernetes-int-or-string: true
191+
privateAS:
192+
description: PrivateAS, when set to true, targets
193+
all private AS numbers in the path for replacement.
194+
type: boolean
195+
replacement:
196+
anyOf:
197+
- type: integer
198+
- type: string
199+
description: |-
200+
Replacement is the AS number to substitute in place of matched AS numbers.
201+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
202+
x-kubernetes-int-or-string: true
203+
required:
204+
- replacement
205+
type: object
206+
x-kubernetes-validations:
207+
- message: exactly one of privateAS or asNumber
208+
must be specified
209+
rule: has(self.privateAS) != has(self.asNumber)
210+
type: object
211+
x-kubernetes-validations:
212+
- message: at least one AS path action must be specified
213+
rule: has(self.prepend) || has(self.replace) || has(self.asNumber)
142214
setCommunity:
143215
description: SetCommunity configures BGP standard community
144216
attributes.
@@ -175,6 +247,7 @@ spec:
175247
x-kubernetes-validations:
176248
- message: at least one BGP action must be specified
177249
rule: has(self.setCommunity) || has(self.setExtCommunity)
250+
|| has(self.setASPath)
178251
routeDisposition:
179252
description: RouteDisposition specifies whether to accept
180253
or reject the route.

0 commit comments

Comments
 (0)