Skip to content

Commit d5e0632

Browse files
committed
Enable CEL validation for subnet overlaps for Layer2 (C)UDN
Enable overlap checks since k8s 1.33 fixes kubernetes/kubernetes#130441. Signed-off-by: Patryk Diak <[email protected]>
1 parent fa6f7d2 commit d5e0632

File tree

4 files changed

+124
-99
lines changed

4 files changed

+124
-99
lines changed

dist/templates/k8s.ovn.org_clusteruserdefinednetworks.yaml.j2

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,21 @@ spec:
298298
rule: '!has(self.infrastructureSubnets) || !has(self.defaultGatewayIPs)
299299
|| self.defaultGatewayIPs.all(ip, self.infrastructureSubnets.exists(subnet,
300300
cidr(subnet).containsIP(ip)))'
301+
- fieldPath: .reservedSubnets
302+
message: reservedSubnets must be subnetworks of the networks
303+
specified in the subnets field
304+
rule: '!has(self.reservedSubnets) || self.reservedSubnets.all(e,
305+
self.subnets.exists(s, cidr(s).containsCIDR(cidr(e))))'
306+
- fieldPath: .infrastructureSubnets
307+
message: infrastructureSubnets must be subnetworks of the networks
308+
specified in the subnets field
309+
rule: '!has(self.infrastructureSubnets) || self.infrastructureSubnets.all(e,
310+
self.subnets.exists(s, cidr(s).containsCIDR(cidr(e))))'
311+
- message: infrastructureSubnets and reservedSubnets must not
312+
overlap
313+
rule: '!has(self.infrastructureSubnets) || !has(self.reservedSubnets)
314+
|| self.infrastructureSubnets.all(infra, !self.reservedSubnets.exists(reserved,
315+
cidr(infra).containsCIDR(reserved) || cidr(reserved).containsCIDR(infra)))'
301316
layer3:
302317
description: Layer3 is the Layer3 topology configuration.
303318
properties:

dist/templates/k8s.ovn.org_userdefinednetworks.yaml.j2

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,20 @@ spec:
243243
rule: '!has(self.infrastructureSubnets) || !has(self.defaultGatewayIPs)
244244
|| self.defaultGatewayIPs.all(ip, self.infrastructureSubnets.exists(subnet,
245245
cidr(subnet).containsIP(ip)))'
246+
- fieldPath: .reservedSubnets
247+
message: reservedSubnets must be subnetworks of the networks specified
248+
in the subnets field
249+
rule: '!has(self.reservedSubnets) || self.reservedSubnets.all(e,
250+
self.subnets.exists(s, cidr(s).containsCIDR(cidr(e))))'
251+
- fieldPath: .infrastructureSubnets
252+
message: infrastructureSubnets must be subnetworks of the networks
253+
specified in the subnets field
254+
rule: '!has(self.infrastructureSubnets) || self.infrastructureSubnets.all(e,
255+
self.subnets.exists(s, cidr(s).containsCIDR(cidr(e))))'
256+
- message: infrastructureSubnets and reservedSubnets must not overlap
257+
rule: '!has(self.infrastructureSubnets) || !has(self.reservedSubnets)
258+
|| self.infrastructureSubnets.all(infra, !self.reservedSubnets.exists(reserved,
259+
cidr(infra).containsCIDR(reserved) || cidr(reserved).containsCIDR(infra)))'
246260
layer3:
247261
description: Layer3 is the Layer3 topology configuration.
248262
properties:

go-controller/pkg/crd/userdefinednetwork/v1/shared.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,9 @@ type Layer3Subnet struct {
9999
// +kubebuilder:validation:XValidation:rule="!has(self.infrastructureSubnets) || has(self.subnets)", message="infrastructureSubnets must be unset when subnets is unset"
100100
// +kubebuilder:validation:XValidation:rule="!has(self.infrastructureSubnets) || has(self.role) && self.role == 'Primary'", message="infrastructureSubnets is only supported for Primary network"
101101
// +kubebuilder:validation:XValidation:rule="!has(self.infrastructureSubnets) || !has(self.defaultGatewayIPs) || self.defaultGatewayIPs.all(ip, self.infrastructureSubnets.exists(subnet, cidr(subnet).containsIP(ip)))", message="defaultGatewayIPs have to belong to infrastructureSubnets"
102-
//
103-
// TODO: Re-enable when CEL validation is supported
104-
// // +kubebuilder:validation:XValidation:rule="!has(self.reservedSubnets) || self.reservedSubnets.all(e, self.subnets.exists(s, cidr(s).containsCIDR(cidr(e))))",message="reservedSubnets must be subnetworks of the networks specified in the subnets field",fieldPath=".reservedSubnets"
105-
// // +kubebuilder:validation:XValidation:rule="!has(self.infrastructureSubnets) || self.infrastructureSubnets.all(e, self.subnets.exists(s, cidr(s).containsCIDR(cidr(e))))",message="infrastructureSubnets must be subnetworks of the networks specified in the subnets field",fieldPath=".infrastructureSubnets"
106-
// // +kubebuilder:validation:XValidation:rule="!has(self.infrastructureSubnets) || !has(self.reservedSubnets) || self.infrastructureSubnets.all(infra, !self.reservedSubnets.exists(reserved, cidr(infra).containsCIDR(reserved) || cidr(reserved).containsCIDR(infra)))", message="infrastructureSubnets and reservedSubnets must not overlap"
102+
// +kubebuilder:validation:XValidation:rule="!has(self.reservedSubnets) || self.reservedSubnets.all(e, self.subnets.exists(s, cidr(s).containsCIDR(cidr(e))))",message="reservedSubnets must be subnetworks of the networks specified in the subnets field",fieldPath=".reservedSubnets"
103+
// +kubebuilder:validation:XValidation:rule="!has(self.infrastructureSubnets) || self.infrastructureSubnets.all(e, self.subnets.exists(s, cidr(s).containsCIDR(cidr(e))))",message="infrastructureSubnets must be subnetworks of the networks specified in the subnets field",fieldPath=".infrastructureSubnets"
104+
// +kubebuilder:validation:XValidation:rule="!has(self.infrastructureSubnets) || !has(self.reservedSubnets) || self.infrastructureSubnets.all(infra, !self.reservedSubnets.exists(reserved, cidr(infra).containsCIDR(reserved) || cidr(reserved).containsCIDR(infra)))", message="infrastructureSubnets and reservedSubnets must not overlap"
107105
type Layer2Config struct {
108106
// Role describes the network role in the pod.
109107
//

test/e2e/testscenario/cudn/invalid-scenarios-layer2.go

Lines changed: 92 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -115,100 +115,98 @@ spec:
115115
mode: Disabled
116116
`,
117117
},
118-
// TODO: enable the below test case once the following issue is resolved https://github.com/kubernetes/kubernetes/issues/130441 and the validation is enabled
119-
// {
120-
// Description: "infrastructureSubnets and reservedSubnets must not overlap",
121-
// ExpectedErr: `infrastructureSubnets and reservedSubnets must not overlap`,
122-
// Manifest: `
123-
// apiVersion: k8s.ovn.org/v1
124-
// kind: ClusterUserDefinedNetwork
125-
// metadata:
126-
// name: infra-reserved-overlap-fail
127-
// spec:
128-
// namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: red}}
129-
// network:
130-
// topology: Layer2
131-
// layer2:
132-
// role: Primary
133-
// subnets: ["192.168.1.0/24"]
134-
// infrastructureSubnets: ["192.168.1.0/28"]
135-
// reservedSubnets: ["192.168.1.8/29"]
136-
// `,
137-
// },
138-
// {
139-
// Description: "dual-stack infrastructureSubnets and reservedSubnets overlap",
140-
// ExpectedErr: `infrastructureSubnets and reservedSubnets must not overlap`,
141-
// Manifest: `
142-
// apiVersion: k8s.ovn.org/v1
143-
// kind: ClusterUserDefinedNetwork
144-
// metadata:
145-
// name: dual-stack-overlap-fail
146-
// spec:
147-
// namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: red}}
148-
// network:
149-
// topology: Layer2
150-
// layer2:
151-
// role: Primary
152-
// subnets: ["192.168.1.0/24", "2001:db8::/64"]
153-
// infrastructureSubnets: ["192.168.1.0/28", "2001:db8::/80"]
154-
// reservedSubnets: ["192.168.1.8/29", "2001:db8::/80"]
155-
// `,
156-
// },
157-
// {
158-
// Description: "reservedSubnets must be subnetworks of subnets",
159-
// ExpectedErr: `reservedSubnets must be subnetworks of the networks specified in the subnets field`,
160-
// Manifest: `
161-
//apiVersion: k8s.ovn.org/v1
162-
//kind: ClusterUserDefinedNetwork
163-
//metadata:
164-
// name: reserved-subnets-outside-fail
165-
//spec:
166-
// namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: red}}
167-
// network:
168-
// topology: Layer2
169-
// layer2:
170-
// role: Secondary
171-
// subnets: ["192.168.1.0/24"]
172-
// reservedSubnets: ["10.0.0.0/28"]
173-
//`,
174-
// },
175-
// {
176-
// Description: "infrastructureSubnets must be subnetworks of subnets",
177-
// ExpectedErr: `infrastructureSubnets must be subnetworks of the networks specified in the subnets field`,
178-
// Manifest: `
179-
//apiVersion: k8s.ovn.org/v1
180-
//kind: ClusterUserDefinedNetwork
181-
//metadata:
182-
// name: infra-subnets-outside-fail
183-
//spec:
184-
// namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: red}}
185-
// network:
186-
// topology: Layer2
187-
// layer2:
188-
// role: Primary
189-
// subnets: ["192.168.1.0/24"]
190-
// infrastructureSubnets: ["10.0.0.0/28"]
191-
//`,
192-
// },
193-
// {
194-
// Description: "IPv6 reservedSubnet outside main subnet",
195-
// ExpectedErr: `reservedSubnets must be subnetworks of the networks specified in the subnets field`,
196-
// Manifest: `
197-
//apiVersion: k8s.ovn.org/v1
198-
//kind: ClusterUserDefinedNetwork
199-
//metadata:
200-
// name: ipv6-reserved-subnet-fail
201-
//spec:
202-
// namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: red}}
203-
// network:
204-
// topology: Layer2
205-
// layer2:
206-
// role: Secondary
207-
// subnets: ["2001:db8::/64"]
208-
// reservedSubnets: ["2001:db9::/80"]
209-
//`,
210-
// },
211-
118+
{
119+
Description: "infrastructureSubnets and reservedSubnets must not overlap",
120+
ExpectedErr: `infrastructureSubnets and reservedSubnets must not overlap`,
121+
Manifest: `
122+
apiVersion: k8s.ovn.org/v1
123+
kind: ClusterUserDefinedNetwork
124+
metadata:
125+
name: infra-reserved-overlap-fail
126+
spec:
127+
namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: red}}
128+
network:
129+
topology: Layer2
130+
layer2:
131+
role: Primary
132+
subnets: ["192.168.1.0/24"]
133+
infrastructureSubnets: ["192.168.1.0/28"]
134+
reservedSubnets: ["192.168.1.8/29"]
135+
`,
136+
},
137+
{
138+
Description: "dual-stack infrastructureSubnets and reservedSubnets overlap",
139+
ExpectedErr: `infrastructureSubnets and reservedSubnets must not overlap`,
140+
Manifest: `
141+
apiVersion: k8s.ovn.org/v1
142+
kind: ClusterUserDefinedNetwork
143+
metadata:
144+
name: dual-stack-overlap-fail
145+
spec:
146+
namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: red}}
147+
network:
148+
topology: Layer2
149+
layer2:
150+
role: Primary
151+
subnets: ["192.168.1.0/24", "2001:db8::/64"]
152+
infrastructureSubnets: ["192.168.1.0/28", "2001:db8::/80"]
153+
reservedSubnets: ["192.168.1.8/29", "2001:db8::/80"]
154+
`,
155+
},
156+
{
157+
Description: "reservedSubnets must be subnetworks of subnets",
158+
ExpectedErr: `reservedSubnets must be subnetworks of the networks specified in the subnets field`,
159+
Manifest: `
160+
apiVersion: k8s.ovn.org/v1
161+
kind: ClusterUserDefinedNetwork
162+
metadata:
163+
name: reserved-subnets-outside-fail
164+
spec:
165+
namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: red}}
166+
network:
167+
topology: Layer2
168+
layer2:
169+
role: Secondary
170+
subnets: ["192.168.1.0/24"]
171+
reservedSubnets: ["10.0.0.0/28"]
172+
`,
173+
},
174+
{
175+
Description: "infrastructureSubnets must be subnetworks of subnets",
176+
ExpectedErr: `infrastructureSubnets must be subnetworks of the networks specified in the subnets field`,
177+
Manifest: `
178+
apiVersion: k8s.ovn.org/v1
179+
kind: ClusterUserDefinedNetwork
180+
metadata:
181+
name: infra-subnets-outside-fail
182+
spec:
183+
namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: red}}
184+
network:
185+
topology: Layer2
186+
layer2:
187+
role: Primary
188+
subnets: ["192.168.1.0/24"]
189+
infrastructureSubnets: ["10.0.0.0/28"]
190+
`,
191+
},
192+
{
193+
Description: "IPv6 reservedSubnet outside main subnet",
194+
ExpectedErr: `reservedSubnets must be subnetworks of the networks specified in the subnets field`,
195+
Manifest: `
196+
apiVersion: k8s.ovn.org/v1
197+
kind: ClusterUserDefinedNetwork
198+
metadata:
199+
name: ipv6-reserved-subnet-fail
200+
spec:
201+
namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: red}}
202+
network:
203+
topology: Layer2
204+
layer2:
205+
role: Secondary
206+
subnets: ["2001:db8::/64"]
207+
reservedSubnets: ["2001:db9::/80"]
208+
`,
209+
},
212210
{
213211
Description: "IPv6 defaultGatewayIP outside subnet",
214212
ExpectedErr: `defaultGatewayIPs must belong to one of the subnets specified in the subnets field`,

0 commit comments

Comments
 (0)