Skip to content

Commit 3f5caeb

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, 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.
1 parent d5135f7 commit 3f5caeb

18 files changed

Lines changed: 694 additions & 1 deletion

api/core/v1alpha1/routingpolicy_types.go

Lines changed: 63 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,67 @@ 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+
// Not all providers may support this action.
112+
// +optional
113+
SetASPath *SetASPathAction `json:"setASPath,omitempty"`
114+
}
115+
116+
// SetASPathAction defines actions to modify the BGP AS path attribute.
117+
// +kubebuilder:validation:XValidation:rule="has(self.prepend) || has(self.replace) || has(self.asNumber)",message="at least one AS path action must be specified"
118+
type SetASPathAction struct {
119+
// Prepend configures prepending to the AS path.
120+
// +optional
121+
Prepend *SetASPathPrepend `json:"prepend,omitempty"`
122+
123+
// Replace configures replacement of AS numbers in the AS path.
124+
// +optional
125+
Replace *SetASPathReplace `json:"replace,omitempty"`
126+
127+
// ASNumber sets the AS path to the specified AS number.
128+
// Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
129+
// +optional
130+
ASNumber *intstr.IntOrString `json:"asNumber,omitempty"`
131+
}
132+
133+
// SetASPathPrepend configures prepending to the BGP AS path.
134+
// Either asNumber or useLastAS must be specified, but not both.
135+
// +kubebuilder:validation:XValidation:rule="has(self.asNumber) != has(self.useLastAS)",message="exactly one of asNumber or useLastAS must be specified"
136+
type SetASPathPrepend struct {
137+
// ASNumber is the autonomous system number to prepend to the AS path.
138+
// Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
139+
// Mutually exclusive with useLastAS.
140+
// +optional
141+
ASNumber *intstr.IntOrString `json:"asNumber,omitempty"`
142+
143+
// UseLastAS prepends the last AS number in the existing AS path the specified number of times.
144+
// Mutually exclusive with asNumber.
145+
// +optional
146+
// +kubebuilder:validation:Minimum=1
147+
// +kubebuilder:validation:Maximum=10
148+
UseLastAS *int32 `json:"useLastAS,omitempty"`
149+
}
150+
151+
// SetASPathReplace configures replacement of AS numbers in the BGP AS path.
152+
// Either privateAS or asNumber must be specified, but not both.
153+
// +kubebuilder:validation:XValidation:rule="has(self.privateAS) != has(self.asNumber)",message="exactly one of privateAS or asNumber must be specified"
154+
type SetASPathReplace struct {
155+
// PrivateAS, when set to true, targets all private AS numbers in the path for replacement.
156+
// Mutually exclusive with asNumber.
157+
// +optional
158+
PrivateAS bool `json:"privateAS,omitempty"`
159+
160+
// ASNumber targets a specific AS number in the path for replacement.
161+
// Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
162+
// Mutually exclusive with privateAS.
163+
// +optional
164+
ASNumber *intstr.IntOrString `json:"asNumber,omitempty"`
165+
166+
// Replacement is the AS number to substitute in place of matched AS numbers.
167+
// Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
168+
// +required
169+
Replacement intstr.IntOrString `json:"replacement"`
108170
}
109171

110172
// 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
@@ -138,6 +138,82 @@ spec:
138138
BgpActions specifies BGP-specific actions to apply when the route is accepted.
139139
Only applicable when RouteDisposition is AcceptRoute.
140140
properties:
141+
setASPath:
142+
description: |-
143+
SetASPath configures modifications to the BGP AS path attribute.
144+
Not all providers may support this action.
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+
Mutually exclusive with useLastAS.
166+
x-kubernetes-int-or-string: true
167+
useLastAS:
168+
description: |-
169+
UseLastAS prepends the last AS number in the existing AS path the specified number of times.
170+
Mutually exclusive with asNumber.
171+
format: int32
172+
maximum: 10
173+
minimum: 1
174+
type: integer
175+
type: object
176+
x-kubernetes-validations:
177+
- message: exactly one of asNumber or useLastAS
178+
must be specified
179+
rule: has(self.asNumber) != has(self.useLastAS)
180+
replace:
181+
description: Replace configures replacement of AS
182+
numbers in the AS path.
183+
properties:
184+
asNumber:
185+
anyOf:
186+
- type: integer
187+
- type: string
188+
description: |-
189+
ASNumber targets a specific AS number in the path for replacement.
190+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
191+
Mutually exclusive with privateAS.
192+
x-kubernetes-int-or-string: true
193+
privateAS:
194+
description: |-
195+
PrivateAS, when set to true, targets all private AS numbers in the path for replacement.
196+
Mutually exclusive with asNumber.
197+
type: boolean
198+
replacement:
199+
anyOf:
200+
- type: integer
201+
- type: string
202+
description: |-
203+
Replacement is the AS number to substitute in place of matched AS numbers.
204+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
205+
x-kubernetes-int-or-string: true
206+
required:
207+
- replacement
208+
type: object
209+
x-kubernetes-validations:
210+
- message: exactly one of privateAS or asNumber
211+
must be specified
212+
rule: has(self.privateAS) != has(self.asNumber)
213+
type: object
214+
x-kubernetes-validations:
215+
- message: at least one AS path action must be specified
216+
rule: has(self.prepend) || has(self.replace) || has(self.asNumber)
141217
setCommunity:
142218
description: SetCommunity configures BGP standard community
143219
attributes.
@@ -174,6 +250,7 @@ spec:
174250
x-kubernetes-validations:
175251
- message: at least one BGP action must be specified
176252
rule: has(self.setCommunity) || has(self.setExtCommunity)
253+
|| has(self.setASPath)
177254
routeDisposition:
178255
description: RouteDisposition specifies whether to accept
179256
or reject the route.

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

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,82 @@ spec:
135135
BgpActions specifies BGP-specific actions to apply when the route is accepted.
136136
Only applicable when RouteDisposition is AcceptRoute.
137137
properties:
138+
setASPath:
139+
description: |-
140+
SetASPath configures modifications to the BGP AS path attribute.
141+
Not all providers may support this action.
142+
properties:
143+
asNumber:
144+
anyOf:
145+
- type: integer
146+
- type: string
147+
description: |-
148+
ASNumber sets the AS path to the specified AS number.
149+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
150+
x-kubernetes-int-or-string: true
151+
prepend:
152+
description: Prepend configures prepending to the
153+
AS path.
154+
properties:
155+
asNumber:
156+
anyOf:
157+
- type: integer
158+
- type: string
159+
description: |-
160+
ASNumber is the autonomous system number to prepend to the AS path.
161+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
162+
Mutually exclusive with useLastAS.
163+
x-kubernetes-int-or-string: true
164+
useLastAS:
165+
description: |-
166+
UseLastAS prepends the last AS number in the existing AS path the specified number of times.
167+
Mutually exclusive with asNumber.
168+
format: int32
169+
maximum: 10
170+
minimum: 1
171+
type: integer
172+
type: object
173+
x-kubernetes-validations:
174+
- message: exactly one of asNumber or useLastAS
175+
must be specified
176+
rule: has(self.asNumber) != has(self.useLastAS)
177+
replace:
178+
description: Replace configures replacement of AS
179+
numbers in the AS path.
180+
properties:
181+
asNumber:
182+
anyOf:
183+
- type: integer
184+
- type: string
185+
description: |-
186+
ASNumber targets a specific AS number in the path for replacement.
187+
Supports both plain format (1-4294967295) and dotted notation (1-65535.0-65535) as per RFC 5396.
188+
Mutually exclusive with privateAS.
189+
x-kubernetes-int-or-string: true
190+
privateAS:
191+
description: |-
192+
PrivateAS, when set to true, targets all private AS numbers in the path for replacement.
193+
Mutually exclusive with asNumber.
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)
138214
setCommunity:
139215
description: SetCommunity configures BGP standard community
140216
attributes.
@@ -171,6 +247,7 @@ spec:
171247
x-kubernetes-validations:
172248
- message: at least one BGP action must be specified
173249
rule: has(self.setCommunity) || has(self.setExtCommunity)
250+
|| has(self.setASPath)
174251
routeDisposition:
175252
description: RouteDisposition specifies whether to accept
176253
or reject the route.

0 commit comments

Comments
 (0)