From df12e4904452f0fb7b68fffd2475f65cdd86313d Mon Sep 17 00:00:00 2001 From: Scot Wells Date: Mon, 24 Aug 2026 14:39:03 -0500 Subject: [PATCH] fix: allow full-width route targets on BGPVRFInstance A route target's local administrator is a four-byte value when paired with a two-byte ASN, so it needs ten digits. The CEL rule capped both halves at nine, which rejects everything from 1000000000 up -- about three quarters of the range. Callers that derive the value from the low 32 bits of an identifier hit this constantly. galactic's CNI does exactly that, and a VPC whose low word lands above 1e9 fails its attachment with "value must be in ASN:NN or IP:NN format" even though the value it built is a legal route target. Widen both halves to ten digits. MaxLength=21 already accommodates the longest legal pair. Co-Authored-By: Claude Opus 5 (1M context) --- api/v1alpha1/vrf_types.go | 2 +- ...network.datumapis.com_bgpvrfinstances.yaml | 4 +-- .../bgp-vrf-crd-schema/chainsaw-test.yaml | 30 +++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/api/v1alpha1/vrf_types.go b/api/v1alpha1/vrf_types.go index 3da8fa2..c314309 100644 --- a/api/v1alpha1/vrf_types.go +++ b/api/v1alpha1/vrf_types.go @@ -86,7 +86,7 @@ type NPTv6Spec struct { // RouteTarget is a BGP extended community in "ASN:NN" or "IP:NN" format. // -// +kubebuilder:validation:XValidation:rule="self.value.matches('^([0-9]{1,9}[.][0-9]{1,9}[.][0-9]{1,9}[.][0-9]{1,9}|[0-9]{1,9}):[0-9]{1,9}$')",message="value must be in ASN:NN or IP:NN format" +// +kubebuilder:validation:XValidation:rule="self.value.matches('^([0-9]{1,9}[.][0-9]{1,9}[.][0-9]{1,9}[.][0-9]{1,9}|[0-9]{1,10}):[0-9]{1,10}$')",message="value must be in ASN:NN or IP:NN format" type RouteTarget struct { // Value is the route target extended community string. // Format: "ASN:NN" (e.g. "65000:100") or "IP:NN" (e.g. "192.0.2.1:100"). diff --git a/config/crd/network.datumapis.com_bgpvrfinstances.yaml b/config/crd/network.datumapis.com_bgpvrfinstances.yaml index dec5d35..fd185bb 100644 --- a/config/crd/network.datumapis.com_bgpvrfinstances.yaml +++ b/config/crd/network.datumapis.com_bgpvrfinstances.yaml @@ -70,7 +70,7 @@ spec: type: object x-kubernetes-validations: - message: value must be in ASN:NN or IP:NN format - rule: self.value.matches('^([0-9]{1,9}[.][0-9]{1,9}[.][0-9]{1,9}[.][0-9]{1,9}|[0-9]{1,9}):[0-9]{1,9}$') + rule: self.value.matches('^([0-9]{1,9}[.][0-9]{1,9}[.][0-9]{1,9}[.][0-9]{1,9}|[0-9]{1,10}):[0-9]{1,10}$') maxItems: 32 minItems: 1 type: array @@ -94,7 +94,7 @@ spec: type: object x-kubernetes-validations: - message: value must be in ASN:NN or IP:NN format - rule: self.value.matches('^([0-9]{1,9}[.][0-9]{1,9}[.][0-9]{1,9}[.][0-9]{1,9}|[0-9]{1,9}):[0-9]{1,9}$') + rule: self.value.matches('^([0-9]{1,9}[.][0-9]{1,9}[.][0-9]{1,9}[.][0-9]{1,9}|[0-9]{1,10}):[0-9]{1,10}$') maxItems: 32 minItems: 1 type: array diff --git a/test/e2e/tests/bgp-vrf-crd-schema/chainsaw-test.yaml b/test/e2e/tests/bgp-vrf-crd-schema/chainsaw-test.yaml index 8acf184..b2d0ded 100644 --- a/test/e2e/tests/bgp-vrf-crd-schema/chainsaw-test.yaml +++ b/test/e2e/tests/bgp-vrf-crd-schema/chainsaw-test.yaml @@ -182,6 +182,36 @@ spec: echo "OK: vrfID above 65535 correctly rejected" echo "Server response: $OUTPUT" + - name: accept-max-uint32-route-target + try: + - apply: + resource: + apiVersion: network.datumapis.com/v1alpha1 + kind: BGPVRFInstance + metadata: + name: e2e-vrf-rt-max + spec: + routerRef: + name: bgp-e2e-worker + vrfID: 100 + # A 2-byte-ASN route target's local administrator is a full + # 4-byte value, so it needs ten digits. Callers derive it from + # the low 32 bits of an identifier, which lands above 1e9 for + # roughly three quarters of the space. + importRouteTargets: + - value: "65000:4294967295" + exportRouteTargets: + - value: "65000:4294967295" + - assert: + resource: + apiVersion: network.datumapis.com/v1alpha1 + kind: BGPVRFInstance + metadata: + name: e2e-vrf-rt-max + spec: + importRouteTargets: + - value: "65000:4294967295" + - name: reject-invalid-rt-format try: - script: