From bee314be9ccd8937e16d22722744d5dce7bb8a0b Mon Sep 17 00:00:00 2001 From: Ben Pickard Date: Fri, 17 Feb 2023 09:34:30 -0500 Subject: [PATCH 1/3] Allow users to specify Gateway Subnet We currently reserve a range of addresses to configure host to service traffic internally in ovn. We need to allow users to specify this range to avoid conflicting with addresses they use in their local infra Signed-off-by: Ben Pickard --- .../generated_openapi/zz_generated.openapi.go | 14 ++++++++++++++ openapi/openapi.json | 8 ++++++++ ...000_70_cluster-network-operator_01.crd.yaml | 6 ++++++ operator/v1/types_network.go | 18 ++++++++++++++++++ .../v1/zz_generated.swagger_doc_generated.go | 8 +++++--- 5 files changed, 51 insertions(+), 3 deletions(-) diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index db1f8d85e83..2816ca15177 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -42963,6 +42963,20 @@ func schema_openshift_api_operator_v1_GatewayConfig(ref common.ReferenceCallback Format: "", }, }, + "v4InternalMasqueradeSubnet": { + SchemaProps: spec.SchemaProps{ + Description: "V4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). The default subnet is 169.254.169.0/29", + Type: []string{"string"}, + Format: "", + }, + }, + "v6InternalMasqueradeSubnet": { + SchemaProps: spec.SchemaProps{ + Description: "V6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). The default subnet is fd69::/125", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, diff --git a/openapi/openapi.json b/openapi/openapi.json index 75584cd9c3d..42a0e663bb3 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -25116,6 +25116,14 @@ "routingViaHost": { "description": "RoutingViaHost allows pod egress traffic to exit via the ovn-k8s-mp0 management port into the host before sending it out. If this is not set, traffic will always egress directly from OVN to outside without touching the host stack. Setting this to true means hardware offload will not be supported. Default is false if GatewayConfig is specified.", "type": "boolean" + }, + "v4InternalMasqueradeSubnet": { + "description": "V4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). The default subnet is 169.254.169.0/29", + "type": "string" + }, + "v6InternalMasqueradeSubnet": { + "description": "V6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). The default subnet is fd69::/125", + "type": "string" } } }, diff --git a/operator/v1/0000_70_cluster-network-operator_01.crd.yaml b/operator/v1/0000_70_cluster-network-operator_01.crd.yaml index 0d944cbcd71..255c934d3ca 100644 --- a/operator/v1/0000_70_cluster-network-operator_01.crd.yaml +++ b/operator/v1/0000_70_cluster-network-operator_01.crd.yaml @@ -223,6 +223,12 @@ spec: description: RoutingViaHost allows pod egress traffic to exit via the ovn-k8s-mp0 management port into the host before sending it out. If this is not set, traffic will always egress directly from OVN to outside without touching the host stack. Setting this to true means hardware offload will not be supported. Default is false if GatewayConfig is specified. type: boolean default: false + v4InternalMasqueradeSubnet: + description: V4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). The default subnet is 169.254.169.0/29 + type: string + v6InternalMasqueradeSubnet: + description: V6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). The default subnet is fd69::/125 + type: string genevePort: description: geneve port is the UDP port to be used by geneve encapulation. Default is 6081 type: integer diff --git a/operator/v1/types_network.go b/operator/v1/types_network.go index ffa8e063629..14c7b9952e2 100644 --- a/operator/v1/types_network.go +++ b/operator/v1/types_network.go @@ -507,6 +507,24 @@ type GatewayConfig struct { // The supported values are "Restricted" and "Global". // +optional IPForwarding IPForwardingMode `json:"ipForwarding,omitempty"` + // V4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by + // ovn-kubernetes to enable host to service traffic. The host is configured with these + // addresses, as well as the shared gateway bridge interface. The values can be changed after + // installation. The subnet chosen should not overlap with other networks specified for + // OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must + // be large enough to accommodate 6 IPs (maximum prefix length /29). + // The default subnet is 169.254.169.0/29 + // +optional + V4InternalMasqueradeSubnet string `json:"v4InternalMasqueradeSubnet,omitempty"` + // V6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by + // ovn-kubernetes to enable host to service traffic. The host is configured with these + // addresses, as well as the shared gateway bridge interface. The values can be changed after + // installation. The subnet chosen should not overlap with other networks specified for + // OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must + // be large enough to accommodate 6 IPs (maximum prefix length /125). + // The default subnet is fd69::/125 + // +optional + V6InternalMasqueradeSubnet string `json:"v6InternalMasqueradeSubnet,omitempty"` } type ExportNetworkFlows struct { diff --git a/operator/v1/zz_generated.swagger_doc_generated.go b/operator/v1/zz_generated.swagger_doc_generated.go index f3ebb503ea5..1ee8f12fda2 100644 --- a/operator/v1/zz_generated.swagger_doc_generated.go +++ b/operator/v1/zz_generated.swagger_doc_generated.go @@ -1298,9 +1298,11 @@ func (FeaturesMigration) SwaggerDoc() map[string]string { } var map_GatewayConfig = map[string]string{ - "": "GatewayConfig holds node gateway-related parsed config file parameters and command-line overrides", - "routingViaHost": "RoutingViaHost allows pod egress traffic to exit via the ovn-k8s-mp0 management port into the host before sending it out. If this is not set, traffic will always egress directly from OVN to outside without touching the host stack. Setting this to true means hardware offload will not be supported. Default is false if GatewayConfig is specified.", - "ipForwarding": "IPForwarding controls IP forwarding for all traffic on OVN-Kubernetes managed interfaces (such as br-ex). By default this is set to Restricted, and Kubernetes related traffic is still forwarded appropriately, but other IP traffic will not be routed by the OCP node. If there is a desire to allow the host to forward traffic across OVN-Kubernetes managed interfaces, then set this field to \"Global\". The supported values are \"Restricted\" and \"Global\".", + "": "GatewayConfig holds node gateway-related parsed config file parameters and command-line overrides", + "routingViaHost": "RoutingViaHost allows pod egress traffic to exit via the ovn-k8s-mp0 management port into the host before sending it out. If this is not set, traffic will always egress directly from OVN to outside without touching the host stack. Setting this to true means hardware offload will not be supported. Default is false if GatewayConfig is specified.", + "ipForwarding": "IPForwarding controls IP forwarding for all traffic on OVN-Kubernetes managed interfaces (such as br-ex). By default this is set to Restricted, and Kubernetes related traffic is still forwarded appropriately, but other IP traffic will not be routed by the OCP node. If there is a desire to allow the host to forward traffic across OVN-Kubernetes managed interfaces, then set this field to \"Global\". The supported values are \"Restricted\" and \"Global\".", + "v4InternalMasqueradeSubnet": "V4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). The default subnet is 169.254.169.0/29", + "v6InternalMasqueradeSubnet": "V6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). The default subnet is fd69::/125", } func (GatewayConfig) SwaggerDoc() map[string]string { From ff31eaa0510fffdfbff1224b4091f1af3d3926b4 Mon Sep 17 00:00:00 2001 From: Ben Pickard Date: Thu, 10 Aug 2023 15:25:25 -0400 Subject: [PATCH 2/3] Add regex validation to V4/6InternalMasqueradeSubnet Regex validation for user passed in subnets taken from https://github.com/openshift/api/blob/3e3f07aadec46cad1812b122a51ce83559934054/operator/v1/types_ingress.go#L378-L386 Signed-off-by: Ben Pickard --- .../generated_openapi/zz_generated.openapi.go | 56 +++++- openapi/openapi.json | 34 +++- ...00_70_cluster-network-operator_01.crd.yaml | 57 +++++- operator/v1/stable.network.testsuite.yaml | 179 ++++++++++++++++++ operator/v1/types_network.go | 57 +++++- operator/v1/zz_generated.deepcopy.go | 44 ++++- .../v1/zz_generated.swagger_doc_generated.go | 26 ++- 7 files changed, 417 insertions(+), 36 deletions(-) diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index 2816ca15177..236b7bf2435 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -859,6 +859,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/openshift/api/operator/v1.IPAMConfig": schema_openshift_api_operator_v1_IPAMConfig(ref), "github.com/openshift/api/operator/v1.IPFIXConfig": schema_openshift_api_operator_v1_IPFIXConfig(ref), "github.com/openshift/api/operator/v1.IPsecConfig": schema_openshift_api_operator_v1_IPsecConfig(ref), + "github.com/openshift/api/operator/v1.IPv4GatewayConfig": schema_openshift_api_operator_v1_IPv4GatewayConfig(ref), + "github.com/openshift/api/operator/v1.IPv6GatewayConfig": schema_openshift_api_operator_v1_IPv6GatewayConfig(ref), "github.com/openshift/api/operator/v1.IngressController": schema_openshift_api_operator_v1_IngressController(ref), "github.com/openshift/api/operator/v1.IngressControllerCaptureHTTPCookie": schema_openshift_api_operator_v1_IngressControllerCaptureHTTPCookie(ref), "github.com/openshift/api/operator/v1.IngressControllerCaptureHTTPCookieUnion": schema_openshift_api_operator_v1_IngressControllerCaptureHTTPCookieUnion(ref), @@ -42963,23 +42965,23 @@ func schema_openshift_api_operator_v1_GatewayConfig(ref common.ReferenceCallback Format: "", }, }, - "v4InternalMasqueradeSubnet": { + "ipv4": { SchemaProps: spec.SchemaProps{ - Description: "V4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). The default subnet is 169.254.169.0/29", - Type: []string{"string"}, - Format: "", + Description: "ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv4 for details of default values.", + Ref: ref("github.com/openshift/api/operator/v1.IPv4GatewayConfig"), }, }, - "v6InternalMasqueradeSubnet": { + "ipv6": { SchemaProps: spec.SchemaProps{ - Description: "V6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). The default subnet is fd69::/125", - Type: []string{"string"}, - Format: "", + Description: "ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv6 for details of default values.", + Ref: ref("github.com/openshift/api/operator/v1.IPv6GatewayConfig"), }, }, }, }, }, + Dependencies: []string{ + "github.com/openshift/api/operator/v1.IPv4GatewayConfig", "github.com/openshift/api/operator/v1.IPv6GatewayConfig"}, } } @@ -43385,6 +43387,44 @@ func schema_openshift_api_operator_v1_IPsecConfig(ref common.ReferenceCallback) } } +func schema_openshift_api_operator_v1_IPv4GatewayConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "v4InternalMasqueradeSubnet": { + SchemaProps: spec.SchemaProps{ + Description: "v4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is 169.254.169.0/29", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openshift_api_operator_v1_IPv6GatewayConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "v6InternalMasqueradeSubnet": { + SchemaProps: spec.SchemaProps{ + Description: "v6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is fd69::/125", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + func schema_openshift_api_operator_v1_IngressController(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/openapi/openapi.json b/openapi/openapi.json index 42a0e663bb3..dce083c3cc3 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -25113,17 +25113,17 @@ "description": "IPForwarding controls IP forwarding for all traffic on OVN-Kubernetes managed interfaces (such as br-ex). By default this is set to Restricted, and Kubernetes related traffic is still forwarded appropriately, but other IP traffic will not be routed by the OCP node. If there is a desire to allow the host to forward traffic across OVN-Kubernetes managed interfaces, then set this field to \"Global\". The supported values are \"Restricted\" and \"Global\".", "type": "string" }, + "ipv4": { + "description": "ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv4 for details of default values.", + "$ref": "#/definitions/com.github.openshift.api.operator.v1.IPv4GatewayConfig" + }, + "ipv6": { + "description": "ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv6 for details of default values.", + "$ref": "#/definitions/com.github.openshift.api.operator.v1.IPv6GatewayConfig" + }, "routingViaHost": { "description": "RoutingViaHost allows pod egress traffic to exit via the ovn-k8s-mp0 management port into the host before sending it out. If this is not set, traffic will always egress directly from OVN to outside without touching the host stack. Setting this to true means hardware offload will not be supported. Default is false if GatewayConfig is specified.", "type": "boolean" - }, - "v4InternalMasqueradeSubnet": { - "description": "V4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). The default subnet is 169.254.169.0/29", - "type": "string" - }, - "v6InternalMasqueradeSubnet": { - "description": "V6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). The default subnet is fd69::/125", - "type": "string" } } }, @@ -25364,6 +25364,24 @@ "com.github.openshift.api.operator.v1.IPsecConfig": { "type": "object" }, + "com.github.openshift.api.operator.v1.IPv4GatewayConfig": { + "type": "object", + "properties": { + "v4InternalMasqueradeSubnet": { + "description": "v4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is 169.254.169.0/29", + "type": "string" + } + } + }, + "com.github.openshift.api.operator.v1.IPv6GatewayConfig": { + "type": "object", + "properties": { + "v6InternalMasqueradeSubnet": { + "description": "v6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is fd69::/125", + "type": "string" + } + } + }, "com.github.openshift.api.operator.v1.IngressController": { "description": "IngressController describes a managed ingress controller for the cluster. The controller can service OpenShift Route and Kubernetes Ingress resources.\n\nWhen an IngressController is created, a new ingress controller deployment is created to allow external traffic to reach the services that expose Ingress or Route resources. Updating this resource may lead to disruption for public facing network connections as a new ingress controller revision may be rolled out.\n\nhttps://kubernetes.io/docs/concepts/services-networking/ingress-controllers\n\nWhenever possible, sensible defaults for the platform are used. See each field for more details.\n\nCompatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).", "type": "object", diff --git a/operator/v1/0000_70_cluster-network-operator_01.crd.yaml b/operator/v1/0000_70_cluster-network-operator_01.crd.yaml index 255c934d3ca..116bfcee561 100644 --- a/operator/v1/0000_70_cluster-network-operator_01.crd.yaml +++ b/operator/v1/0000_70_cluster-network-operator_01.crd.yaml @@ -219,16 +219,61 @@ spec: ipForwarding: description: IPForwarding controls IP forwarding for all traffic on OVN-Kubernetes managed interfaces (such as br-ex). By default this is set to Restricted, and Kubernetes related traffic is still forwarded appropriately, but other IP traffic will not be routed by the OCP node. If there is a desire to allow the host to forward traffic across OVN-Kubernetes managed interfaces, then set this field to "Global". The supported values are "Restricted" and "Global". type: string + ipv4: + description: ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv4 for details of default values. + type: object + properties: + v4InternalMasqueradeSubnet: + description: v4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is 169.254.169.0/29 + type: string + maxLength: 18 + x-kubernetes-validations: + - rule: self.indexOf('/') == self.lastIndexOf('/') + message: CIDR format must contain exactly one '/' + - rule: '[int(self.split(''/'')[1])].all(x, x <= 29 && x >= 0)' + message: subnet must be in the range /0 to /29 inclusive + - rule: self.split('/')[0].split('.').size() == 4 + message: a valid IPv4 address must contain 4 octets + - rule: '[self.findAll(''[0-9]+'')[0]].all(x, x != ''0'' && int(x) <= 255 && !x.startsWith(''0''))' + message: first IP address octet must not contain leading zeros, must be greater than 0 and less or equal to 255 + - rule: '[self.findAll(''[0-9]+'')[1], self.findAll(''[0-9]+'')[2], self.findAll(''[0-9]+'')[3]].all(x, int(x) <= 255 && (x == ''0'' || !x.startsWith(''0'')))' + message: IP address octets must not contain leading zeros, and must be less or equal to 255 + ipv6: + description: ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv6 for details of default values. + type: object + properties: + v6InternalMasqueradeSubnet: + description: v6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is fd69::/125 + type: string + x-kubernetes-validations: + - rule: self.indexOf('/') == self.lastIndexOf('/') + message: CIDR format must contain exactly one '/' + - rule: self.split('/').size() == 2 && [int(self.split('/')[1])].all(x, x <= 125 && x >= 0) + message: subnet must be in the range /0 to /125 inclusive + - rule: self.indexOf('::') == self.lastIndexOf('::') + message: IPv6 addresses must contain at most one '::' and may only be shortened once + - rule: 'self.contains(''.'') ? self.split(''/'')[0].split('':'').size() <= 6 : self.split(''/'')[0].split('':'').size() <= 8' + message: a valid IPv6 address must contain at most 8 segments, or at most 6 segments for a dual address + - rule: 'self.split(''/'')[0].split('':'').size() >=1 ? [self.split(''/'')[0].split('':'', 8)[0]].all(x, x == '''' || x.matches(''[0-9A-Fa-f]{1,4}'')) : true' + message: each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 1 + - rule: 'self.split(''/'')[0].split('':'').size() >=2 ? [self.split(''/'')[0].split('':'', 8)[1]].all(x, x == '''' || x.matches(''[0-9A-Fa-f]{1,4}'')) : true' + message: each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 2 + - rule: 'self.split(''/'')[0].split('':'').size() >=3 ? [self.split(''/'')[0].split('':'', 8)[2]].all(x, x == '''' || x.matches(''[0-9A-Fa-f]{1,4}'')) : true' + message: each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 3 + - rule: 'self.split(''/'')[0].split('':'').size() >=4 ? [self.split(''/'')[0].split('':'', 8)[3]].all(x, x == '''' || x.matches(''[0-9A-Fa-f]{1,4}'')) : true' + message: each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 4 + - rule: 'self.split(''/'')[0].split('':'').size() >=5 ? [self.split(''/'')[0].split('':'', 8)[4]].all(x, x == '''' || x.matches(''[0-9A-Fa-f]{1,4}'')) : true' + message: each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 5 + - rule: 'self.split(''/'')[0].split('':'').size() >=6 ? [self.split(''/'')[0].split('':'', 8)[5]].all(x, x == '''' || x.matches(''[0-9A-Fa-f]{1,4}'')) : true' + message: each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 6 + - rule: 'self.split(''/'')[0].split('':'').size() >=7 ? [self.split(''/'')[0].split('':'', 8)[6]].all(x, x == '''' || x.matches(''[0-9A-Fa-f]{1,4}'')) : true' + message: each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 7 + - rule: 'self.split(''/'')[0].split('':'').size() >=8 ? [self.split(''/'')[0].split('':'', 8)[7]].all(x, x == '''' || x.matches(''[0-9A-Fa-f]{1,4}'')) : true' + message: each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 8 routingViaHost: description: RoutingViaHost allows pod egress traffic to exit via the ovn-k8s-mp0 management port into the host before sending it out. If this is not set, traffic will always egress directly from OVN to outside without touching the host stack. Setting this to true means hardware offload will not be supported. Default is false if GatewayConfig is specified. type: boolean default: false - v4InternalMasqueradeSubnet: - description: V4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). The default subnet is 169.254.169.0/29 - type: string - v6InternalMasqueradeSubnet: - description: V6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). The default subnet is fd69::/125 - type: string genevePort: description: geneve port is the UDP port to be used by geneve encapulation. Default is 6081 type: integer diff --git a/operator/v1/stable.network.testsuite.yaml b/operator/v1/stable.network.testsuite.yaml index a40c21fabe1..9bc8bac394f 100644 --- a/operator/v1/stable.network.testsuite.yaml +++ b/operator/v1/stable.network.testsuite.yaml @@ -15,3 +15,182 @@ tests: disableNetworkDiagnostics: false logLevel: Normal operatorLogLevel: Normal + - name: Should be able to pass a valid IPV4 CIDR to v4InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv4: + v4InternalMasqueradeSubnet: "169.254.168.0/29" + expected: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + routingViaHost: false + ipv4: + v4InternalMasqueradeSubnet: "169.254.168.0/29" + disableNetworkDiagnostics: false + logLevel: Normal + operatorLogLevel: Normal + - name: Should not be able to pass CIDR with a subnet larger than /29 to v4InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv4: + v4InternalMasqueradeSubnet: 10.10.10.10/32 + expectedError: "Invalid value: \"string\": subnet must be in the range /0 to /29 inclusive" + - name: Should not be able to pass CIDR with a subnet smaller than /0 to v4InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv4: + v4InternalMasqueradeSubnet: 10.10.10.10/-1 + expectedError: "Invalid value: \"string\": subnet must be in the range /0 to /29 inclusive" + - name: Should not be able to add an IP address with the incorrect number of octets to v4InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv4: + v4InternalMasqueradeSubnet: 10.10.10/24 + expectedError: "Invalid value: \"string\": a valid IPv4 address must contain 4 octets" + - name: Should not be able to add an IP address with leading zeros in an octet to v4InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv4: + v4InternalMasqueradeSubnet: 10.10.010.10/24 + expectedError: "Invalid value: \"string\": IP address octets must not contain leading zeros, and must be less or equal to 255" + - name: Should not be able to add an IP address with with zero for the first octet to v4InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv4: + v4InternalMasqueradeSubnet: 0.10.10.10/24 + expectedError: "Invalid value: \"string\": first IP address octet must not contain leading zeros, must be greater than 0 and less or equal to 255" + - name: Should not be able to add an IP address with an octet greater than 255 to v4InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv4: + v4InternalMasqueradeSubnet: 10.10.10.256/24 + expectedError: "Invalid value: \"string\": IP address octets must not contain leading zeros, and must be less or equal to 255" + - name: Should be able to pass a valid IPV6 CIDR to v6InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv6: + v6InternalMasqueradeSubnet: "abcd:ef01:2345:6789:abcd:ef01:2345:6789/125" + expected: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv6: + v6InternalMasqueradeSubnet: "abcd:ef01:2345:6789:abcd:ef01:2345:6789/125" + routingViaHost: false + disableNetworkDiagnostics: false + logLevel: Normal + operatorLogLevel: Normal + - name: Should be able to pass a valid shorthand IPV6 CIDR to v6InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv6: + v6InternalMasqueradeSubnet: "abcd:ef01::2345:6789/20" + expected: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + routingViaHost: false + ipv6: + v6InternalMasqueradeSubnet: "abcd:ef01::2345:6789/20" + disableNetworkDiagnostics: false + logLevel: Normal + operatorLogLevel: Normal + - name: Should not be able to pass invalid IPV6 CIDR to v6InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv6: + v6InternalMasqueradeSubnet: "foo" + expectedError: "Invalid value: \"string\": subnet must be in the range /0 to /125 inclusive" + - name: Should not be able to add an IP address with the incorrect number of octets to v6InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv6: + v6InternalMasqueradeSubnet: abcd:ef01:2345:6789:abcd:ef01:2345:6789:abcd/125 + expectedError: "Invalid value: \"string\": a valid IPv6 address must contain at most 8 segments, or at most 6 segments for a dual address" + - name: Should not be able to add a dual IP address with the incorrect number of octets to v6InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv6: + v6InternalMasqueradeSubnet: abcd:ef01:2345:6789:abcd:ef01:2345:1.2.3.4/125 + expectedError: "Invalid value: \"string\": a valid IPv6 address must contain at most 8 segments, or at most 6 segments for a dual address" + - name: Should be able to pass a double shorthand IPV6 CIDR to v6InternalMasqueradeSubnet + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv6: + v6InternalMasqueradeSubnet: "abcd::ef01::2345:6789/20" + expectedError: "Invalid value: \"string\": IPv6 addresses must contain at most one '::' and may only be shortened once" \ No newline at end of file diff --git a/operator/v1/types_network.go b/operator/v1/types_network.go index 14c7b9952e2..e2316a86a2e 100644 --- a/operator/v1/types_network.go +++ b/operator/v1/types_network.go @@ -507,23 +507,64 @@ type GatewayConfig struct { // The supported values are "Restricted" and "Global". // +optional IPForwarding IPForwardingMode `json:"ipForwarding,omitempty"` - // V4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by - // ovn-kubernetes to enable host to service traffic. The host is configured with these + // ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the defualt + // configuration is used. Check individual members fields within ipv4 for details of default values. + // +optional + IPv4 *IPv4GatewayConfig `json:"ipv4,omitempty"` + // ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the defualt + // configuration is used. Check individual members fields within ipv6 for details of default values. + // +optional + IPv6 *IPv6GatewayConfig `json:"ipv6,omitempty"` +} + +type IPv4GatewayConfig struct { + // v4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by + // ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these // addresses, as well as the shared gateway bridge interface. The values can be changed after // installation. The subnet chosen should not overlap with other networks specified for // OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must // be large enough to accommodate 6 IPs (maximum prefix length /29). - // The default subnet is 169.254.169.0/29 - // +optional + // When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. + // The current default subnet is 169.254.169.0/29 + // +kubebuilder:validation:MaxLength=18 + // +kubebuilder:validation:XValidation:rule="self.indexOf('/') == self.lastIndexOf('/')",message="CIDR format must contain exactly one '/'" + // +kubebuilder:validation:XValidation:rule="[int(self.split('/')[1])].all(x, x <= 29 && x >= 0)",message="subnet must be in the range /0 to /29 inclusive" + // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split('.').size() == 4",message="a valid IPv4 address must contain 4 octets" + // +kubebuilder:validation:XValidation:rule="[self.findAll('[0-9]+')[0]].all(x, x != '0' && int(x) <= 255 && !x.startsWith('0'))",message="first IP address octet must not contain leading zeros, must be greater than 0 and less or equal to 255" + // +kubebuilder:validation:XValidation:rule="[self.findAll('[0-9]+')[1], self.findAll('[0-9]+')[2], self.findAll('[0-9]+')[3]].all(x, int(x) <= 255 && (x == '0' || !x.startsWith('0')))",message="IP address octets must not contain leading zeros, and must be less or equal to 255" + // +optional + // + --- + // + The regex for the IPV4 CIDR range was taken from other feilds in the Openshift API + // + The value must be in IPV4 CIDR format V4InternalMasqueradeSubnet string `json:"v4InternalMasqueradeSubnet,omitempty"` - // V6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by - // ovn-kubernetes to enable host to service traffic. The host is configured with these +} + +type IPv6GatewayConfig struct { + // v6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by + // ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these // addresses, as well as the shared gateway bridge interface. The values can be changed after // installation. The subnet chosen should not overlap with other networks specified for // OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must // be large enough to accommodate 6 IPs (maximum prefix length /125). - // The default subnet is fd69::/125 - // +optional + // When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. + // The current default subnet is fd69::/125 + // +kubebuilder:validation:XValidation:rule="self.indexOf('/') == self.lastIndexOf('/')",message="CIDR format must contain exactly one '/'" + // +kubebuilder:validation:XValidation:rule="self.split('/').size() == 2 && [int(self.split('/')[1])].all(x, x <= 125 && x >= 0)",message="subnet must be in the range /0 to /125 inclusive" + // +kubebuilder:validation:XValidation:rule="self.indexOf('::') == self.lastIndexOf('::')",message="IPv6 addresses must contain at most one '::' and may only be shortened once" + // +kubebuilder:validation:XValidation:rule="self.contains('.') ? self.split('/')[0].split(':').size() <= 6 : self.split('/')[0].split(':').size() <= 8",message="a valid IPv6 address must contain at most 8 segments, or at most 6 segments for a dual address" + // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=1 ? [self.split('/')[0].split(':', 8)[0]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 1" + // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=2 ? [self.split('/')[0].split(':', 8)[1]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 2" + // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=3 ? [self.split('/')[0].split(':', 8)[2]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 3" + // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=4 ? [self.split('/')[0].split(':', 8)[3]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 4" + // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=5 ? [self.split('/')[0].split(':', 8)[4]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 5" + // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=6 ? [self.split('/')[0].split(':', 8)[5]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 6" + // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=7 ? [self.split('/')[0].split(':', 8)[6]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 7" + // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=8 ? [self.split('/')[0].split(':', 8)[7]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 8" + // +optional + // + --- + // + The regex for the IPV6 CIDR range was taken from + // + https://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses-cidr-ranges-and-hostnames/ + // + The value must be in IPV6 CIDR format V6InternalMasqueradeSubnet string `json:"v6InternalMasqueradeSubnet,omitempty"` } diff --git a/operator/v1/zz_generated.deepcopy.go b/operator/v1/zz_generated.deepcopy.go index 3f47cd44167..5692e4a6a3b 100644 --- a/operator/v1/zz_generated.deepcopy.go +++ b/operator/v1/zz_generated.deepcopy.go @@ -1533,6 +1533,16 @@ func (in *GCPLoadBalancerParameters) DeepCopy() *GCPLoadBalancerParameters { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GatewayConfig) DeepCopyInto(out *GatewayConfig) { *out = *in + if in.IPv4 != nil { + in, out := &in.IPv4, &out.IPv4 + *out = new(IPv4GatewayConfig) + **out = **in + } + if in.IPv6 != nil { + in, out := &in.IPv6, &out.IPv6 + *out = new(IPv6GatewayConfig) + **out = **in + } return } @@ -1764,6 +1774,38 @@ func (in *IPsecConfig) DeepCopy() *IPsecConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPv4GatewayConfig) DeepCopyInto(out *IPv4GatewayConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPv4GatewayConfig. +func (in *IPv4GatewayConfig) DeepCopy() *IPv4GatewayConfig { + if in == nil { + return nil + } + out := new(IPv4GatewayConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPv6GatewayConfig) DeepCopyInto(out *IPv6GatewayConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPv6GatewayConfig. +func (in *IPv6GatewayConfig) DeepCopy() *IPv6GatewayConfig { + if in == nil { + return nil + } + out := new(IPv6GatewayConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IngressController) DeepCopyInto(out *IngressController) { *out = *in @@ -3216,7 +3258,7 @@ func (in *OVNKubernetesConfig) DeepCopyInto(out *OVNKubernetesConfig) { if in.GatewayConfig != nil { in, out := &in.GatewayConfig, &out.GatewayConfig *out = new(GatewayConfig) - **out = **in + (*in).DeepCopyInto(*out) } in.EgressIPConfig.DeepCopyInto(&out.EgressIPConfig) return diff --git a/operator/v1/zz_generated.swagger_doc_generated.go b/operator/v1/zz_generated.swagger_doc_generated.go index 1ee8f12fda2..480f8a3037d 100644 --- a/operator/v1/zz_generated.swagger_doc_generated.go +++ b/operator/v1/zz_generated.swagger_doc_generated.go @@ -1298,11 +1298,11 @@ func (FeaturesMigration) SwaggerDoc() map[string]string { } var map_GatewayConfig = map[string]string{ - "": "GatewayConfig holds node gateway-related parsed config file parameters and command-line overrides", - "routingViaHost": "RoutingViaHost allows pod egress traffic to exit via the ovn-k8s-mp0 management port into the host before sending it out. If this is not set, traffic will always egress directly from OVN to outside without touching the host stack. Setting this to true means hardware offload will not be supported. Default is false if GatewayConfig is specified.", - "ipForwarding": "IPForwarding controls IP forwarding for all traffic on OVN-Kubernetes managed interfaces (such as br-ex). By default this is set to Restricted, and Kubernetes related traffic is still forwarded appropriately, but other IP traffic will not be routed by the OCP node. If there is a desire to allow the host to forward traffic across OVN-Kubernetes managed interfaces, then set this field to \"Global\". The supported values are \"Restricted\" and \"Global\".", - "v4InternalMasqueradeSubnet": "V4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). The default subnet is 169.254.169.0/29", - "v6InternalMasqueradeSubnet": "V6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. The host is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). The default subnet is fd69::/125", + "": "GatewayConfig holds node gateway-related parsed config file parameters and command-line overrides", + "routingViaHost": "RoutingViaHost allows pod egress traffic to exit via the ovn-k8s-mp0 management port into the host before sending it out. If this is not set, traffic will always egress directly from OVN to outside without touching the host stack. Setting this to true means hardware offload will not be supported. Default is false if GatewayConfig is specified.", + "ipForwarding": "IPForwarding controls IP forwarding for all traffic on OVN-Kubernetes managed interfaces (such as br-ex). By default this is set to Restricted, and Kubernetes related traffic is still forwarded appropriately, but other IP traffic will not be routed by the OCP node. If there is a desire to allow the host to forward traffic across OVN-Kubernetes managed interfaces, then set this field to \"Global\". The supported values are \"Restricted\" and \"Global\".", + "ipv4": "ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv4 for details of default values.", + "ipv6": "ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv6 for details of default values.", } func (GatewayConfig) SwaggerDoc() map[string]string { @@ -1336,6 +1336,22 @@ func (IPFIXConfig) SwaggerDoc() map[string]string { return map_IPFIXConfig } +var map_IPv4GatewayConfig = map[string]string{ + "v4InternalMasqueradeSubnet": "v4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is 169.254.169.0/29 ", +} + +func (IPv4GatewayConfig) SwaggerDoc() map[string]string { + return map_IPv4GatewayConfig +} + +var map_IPv6GatewayConfig = map[string]string{ + "v6InternalMasqueradeSubnet": "v6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is fd69::/125 ", +} + +func (IPv6GatewayConfig) SwaggerDoc() map[string]string { + return map_IPv6GatewayConfig +} + var map_KuryrConfig = map[string]string{ "": "KuryrConfig configures the Kuryr-Kubernetes SDN", "daemonProbesPort": "The port kuryr-daemon will listen for readiness and liveness requests.", From aa0120a6356876246407a87187c507fb21dc56aa Mon Sep 17 00:00:00 2001 From: Ben Pickard Date: Wed, 16 Aug 2023 11:49:00 -0400 Subject: [PATCH 3/3] Extend IPV6 testing Adds tests for KEL expressions for internalMasqueradeSubnet fields Remove redundant ipv4 and ipv6 name for internalMasqueradeSubnet fields inside their respective structs Signed-off-by: Ben Pickard --- .../generated_openapi/zz_generated.openapi.go | 20 ++-- openapi/openapi.json | 16 +-- ...00_70_cluster-network-operator_01.crd.yaml | 18 ++-- operator/v1/stable.network.testsuite.yaml | 98 +++++++++++++------ operator/v1/types_network.go | 30 +++--- operator/v1/zz_generated.deepcopy.go | 14 +-- .../v1/zz_generated.swagger_doc_generated.go | 10 +- 7 files changed, 121 insertions(+), 85 deletions(-) diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index 236b7bf2435..3e6f97551d5 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -42967,13 +42967,15 @@ func schema_openshift_api_operator_v1_GatewayConfig(ref common.ReferenceCallback }, "ipv4": { SchemaProps: spec.SchemaProps{ - Description: "ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv4 for details of default values.", + Description: "ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the default configuration is used. Check individual members fields within ipv4 for details of default values.", + Default: map[string]interface{}{}, Ref: ref("github.com/openshift/api/operator/v1.IPv4GatewayConfig"), }, }, "ipv6": { SchemaProps: spec.SchemaProps{ - Description: "ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv6 for details of default values.", + Description: "ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the default configuration is used. Check individual members fields within ipv6 for details of default values.", + Default: map[string]interface{}{}, Ref: ref("github.com/openshift/api/operator/v1.IPv6GatewayConfig"), }, }, @@ -43391,11 +43393,12 @@ func schema_openshift_api_operator_v1_IPv4GatewayConfig(ref common.ReferenceCall return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "IPV4GatewayConfig holds the configuration paramaters for IPV4 connections in the GatewayConfig for OVN-Kubernetes", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "v4InternalMasqueradeSubnet": { + "internalMasqueradeSubnet": { SchemaProps: spec.SchemaProps{ - Description: "v4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is 169.254.169.0/29", + Description: "internalMasqueradeSubnet contains the masquerade addresses in IPV4 CIDR format used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is 169.254.169.0/29 The value must be in proper IPV4 CIDR format", Type: []string{"string"}, Format: "", }, @@ -43410,11 +43413,12 @@ func schema_openshift_api_operator_v1_IPv6GatewayConfig(ref common.ReferenceCall return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "IPV6GatewayConfig holds the configuration paramaters for IPV6 connections in the GatewayConfig for OVN-Kubernetes", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "v6InternalMasqueradeSubnet": { + "internalMasqueradeSubnet": { SchemaProps: spec.SchemaProps{ - Description: "v6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is fd69::/125", + Description: "internalMasqueradeSubnet contains the masquerade addresses in IPV6 CIDR format used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is fd69::/125 Note that IPV6 dual addresses are not permitted", Type: []string{"string"}, Format: "", }, diff --git a/openapi/openapi.json b/openapi/openapi.json index dce083c3cc3..c1969c5e5e9 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -25114,11 +25114,13 @@ "type": "string" }, "ipv4": { - "description": "ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv4 for details of default values.", + "description": "ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the default configuration is used. Check individual members fields within ipv4 for details of default values.", + "default": {}, "$ref": "#/definitions/com.github.openshift.api.operator.v1.IPv4GatewayConfig" }, "ipv6": { - "description": "ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv6 for details of default values.", + "description": "ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the default configuration is used. Check individual members fields within ipv6 for details of default values.", + "default": {}, "$ref": "#/definitions/com.github.openshift.api.operator.v1.IPv6GatewayConfig" }, "routingViaHost": { @@ -25365,19 +25367,21 @@ "type": "object" }, "com.github.openshift.api.operator.v1.IPv4GatewayConfig": { + "description": "IPV4GatewayConfig holds the configuration paramaters for IPV4 connections in the GatewayConfig for OVN-Kubernetes", "type": "object", "properties": { - "v4InternalMasqueradeSubnet": { - "description": "v4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is 169.254.169.0/29", + "internalMasqueradeSubnet": { + "description": "internalMasqueradeSubnet contains the masquerade addresses in IPV4 CIDR format used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is 169.254.169.0/29 The value must be in proper IPV4 CIDR format", "type": "string" } } }, "com.github.openshift.api.operator.v1.IPv6GatewayConfig": { + "description": "IPV6GatewayConfig holds the configuration paramaters for IPV6 connections in the GatewayConfig for OVN-Kubernetes", "type": "object", "properties": { - "v6InternalMasqueradeSubnet": { - "description": "v6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is fd69::/125", + "internalMasqueradeSubnet": { + "description": "internalMasqueradeSubnet contains the masquerade addresses in IPV6 CIDR format used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is fd69::/125 Note that IPV6 dual addresses are not permitted", "type": "string" } } diff --git a/operator/v1/0000_70_cluster-network-operator_01.crd.yaml b/operator/v1/0000_70_cluster-network-operator_01.crd.yaml index 116bfcee561..83222ab78cb 100644 --- a/operator/v1/0000_70_cluster-network-operator_01.crd.yaml +++ b/operator/v1/0000_70_cluster-network-operator_01.crd.yaml @@ -220,11 +220,11 @@ spec: description: IPForwarding controls IP forwarding for all traffic on OVN-Kubernetes managed interfaces (such as br-ex). By default this is set to Restricted, and Kubernetes related traffic is still forwarded appropriately, but other IP traffic will not be routed by the OCP node. If there is a desire to allow the host to forward traffic across OVN-Kubernetes managed interfaces, then set this field to "Global". The supported values are "Restricted" and "Global". type: string ipv4: - description: ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv4 for details of default values. + description: ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the default configuration is used. Check individual members fields within ipv4 for details of default values. type: object properties: - v4InternalMasqueradeSubnet: - description: v4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is 169.254.169.0/29 + internalMasqueradeSubnet: + description: internalMasqueradeSubnet contains the masquerade addresses in IPV4 CIDR format used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is 169.254.169.0/29 The value must be in proper IPV4 CIDR format type: string maxLength: 18 x-kubernetes-validations: @@ -239,11 +239,11 @@ spec: - rule: '[self.findAll(''[0-9]+'')[1], self.findAll(''[0-9]+'')[2], self.findAll(''[0-9]+'')[3]].all(x, int(x) <= 255 && (x == ''0'' || !x.startsWith(''0'')))' message: IP address octets must not contain leading zeros, and must be less or equal to 255 ipv6: - description: ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv6 for details of default values. + description: ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the default configuration is used. Check individual members fields within ipv6 for details of default values. type: object properties: - v6InternalMasqueradeSubnet: - description: v6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is fd69::/125 + internalMasqueradeSubnet: + description: internalMasqueradeSubnet contains the masquerade addresses in IPV6 CIDR format used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is fd69::/125 Note that IPV6 dual addresses are not permitted type: string x-kubernetes-validations: - rule: self.indexOf('/') == self.lastIndexOf('/') @@ -252,8 +252,8 @@ spec: message: subnet must be in the range /0 to /125 inclusive - rule: self.indexOf('::') == self.lastIndexOf('::') message: IPv6 addresses must contain at most one '::' and may only be shortened once - - rule: 'self.contains(''.'') ? self.split(''/'')[0].split('':'').size() <= 6 : self.split(''/'')[0].split('':'').size() <= 8' - message: a valid IPv6 address must contain at most 8 segments, or at most 6 segments for a dual address + - rule: 'self.contains(''::'') ? self.split(''/'')[0].split('':'').size() <= 8 : self.split(''/'')[0].split('':'').size() == 8' + message: a valid IPv6 address must contain 8 segments unless elided (::), in which case it must contain at most 6 non-empty segments - rule: 'self.split(''/'')[0].split('':'').size() >=1 ? [self.split(''/'')[0].split('':'', 8)[0]].all(x, x == '''' || x.matches(''[0-9A-Fa-f]{1,4}'')) : true' message: each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 1 - rule: 'self.split(''/'')[0].split('':'').size() >=2 ? [self.split(''/'')[0].split('':'', 8)[1]].all(x, x == '''' || x.matches(''[0-9A-Fa-f]{1,4}'')) : true' @@ -270,6 +270,8 @@ spec: message: each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 7 - rule: 'self.split(''/'')[0].split('':'').size() >=8 ? [self.split(''/'')[0].split('':'', 8)[7]].all(x, x == '''' || x.matches(''[0-9A-Fa-f]{1,4}'')) : true' message: each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 8 + - rule: '!self.contains(''.'')' + message: IPv6 dual addresses are not permitted, value should not contain `.` characters routingViaHost: description: RoutingViaHost allows pod egress traffic to exit via the ovn-k8s-mp0 management port into the host before sending it out. If this is not set, traffic will always egress directly from OVN to outside without touching the host stack. Setting this to true means hardware offload will not be supported. Default is false if GatewayConfig is specified. type: boolean diff --git a/operator/v1/stable.network.testsuite.yaml b/operator/v1/stable.network.testsuite.yaml index 9bc8bac394f..698e4bf48c8 100644 --- a/operator/v1/stable.network.testsuite.yaml +++ b/operator/v1/stable.network.testsuite.yaml @@ -15,7 +15,7 @@ tests: disableNetworkDiagnostics: false logLevel: Normal operatorLogLevel: Normal - - name: Should be able to pass a valid IPV4 CIDR to v4InternalMasqueradeSubnet + - name: Should be able to pass a valid IPV4 CIDR to IPV4 internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -24,7 +24,7 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv4: - v4InternalMasqueradeSubnet: "169.254.168.0/29" + internalMasqueradeSubnet: "169.254.168.0/29" expected: | apiVersion: operator.openshift.io/v1 kind: Network @@ -34,11 +34,11 @@ tests: gatewayConfig: routingViaHost: false ipv4: - v4InternalMasqueradeSubnet: "169.254.168.0/29" + internalMasqueradeSubnet: "169.254.168.0/29" disableNetworkDiagnostics: false logLevel: Normal operatorLogLevel: Normal - - name: Should not be able to pass CIDR with a subnet larger than /29 to v4InternalMasqueradeSubnet + - name: Should not be able to pass CIDR with a subnet larger than /29 to IPV4 internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -47,9 +47,9 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv4: - v4InternalMasqueradeSubnet: 10.10.10.10/32 + internalMasqueradeSubnet: 10.10.10.10/32 expectedError: "Invalid value: \"string\": subnet must be in the range /0 to /29 inclusive" - - name: Should not be able to pass CIDR with a subnet smaller than /0 to v4InternalMasqueradeSubnet + - name: Should not be able to pass CIDR with a subnet smaller than /0 to IPV4 internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -58,9 +58,9 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv4: - v4InternalMasqueradeSubnet: 10.10.10.10/-1 + internalMasqueradeSubnet: 10.10.10.10/-1 expectedError: "Invalid value: \"string\": subnet must be in the range /0 to /29 inclusive" - - name: Should not be able to add an IP address with the incorrect number of octets to v4InternalMasqueradeSubnet + - name: Should not be able to add an IP address with the incorrect number of octets to IPV4 internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -69,9 +69,9 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv4: - v4InternalMasqueradeSubnet: 10.10.10/24 + internalMasqueradeSubnet: 10.10.10/24 expectedError: "Invalid value: \"string\": a valid IPv4 address must contain 4 octets" - - name: Should not be able to add an IP address with leading zeros in an octet to v4InternalMasqueradeSubnet + - name: Should not be able to add an IP address with leading zeros in an octet to IPV4 internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -80,9 +80,9 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv4: - v4InternalMasqueradeSubnet: 10.10.010.10/24 + internalMasqueradeSubnet: 10.10.010.10/24 expectedError: "Invalid value: \"string\": IP address octets must not contain leading zeros, and must be less or equal to 255" - - name: Should not be able to add an IP address with with zero for the first octet to v4InternalMasqueradeSubnet + - name: Should not be able to add an IP address with with zero for the first octet to internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -91,9 +91,9 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv4: - v4InternalMasqueradeSubnet: 0.10.10.10/24 + internalMasqueradeSubnet: 0.10.10.10/24 expectedError: "Invalid value: \"string\": first IP address octet must not contain leading zeros, must be greater than 0 and less or equal to 255" - - name: Should not be able to add an IP address with an octet greater than 255 to v4InternalMasqueradeSubnet + - name: Should not be able to add an IP address with an octet greater than 255 to IPV4 internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -102,9 +102,9 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv4: - v4InternalMasqueradeSubnet: 10.10.10.256/24 + internalMasqueradeSubnet: 10.10.10.256/24 expectedError: "Invalid value: \"string\": IP address octets must not contain leading zeros, and must be less or equal to 255" - - name: Should be able to pass a valid IPV6 CIDR to v6InternalMasqueradeSubnet + - name: Should be able to pass a valid IPV6 CIDR to IPV6 internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -113,7 +113,7 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv6: - v6InternalMasqueradeSubnet: "abcd:ef01:2345:6789:abcd:ef01:2345:6789/125" + internalMasqueradeSubnet: "abcd:ef01:2345:6789:abcd:ef01:2345:6789/125" expected: | apiVersion: operator.openshift.io/v1 kind: Network @@ -122,12 +122,12 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv6: - v6InternalMasqueradeSubnet: "abcd:ef01:2345:6789:abcd:ef01:2345:6789/125" + internalMasqueradeSubnet: "abcd:ef01:2345:6789:abcd:ef01:2345:6789/125" routingViaHost: false disableNetworkDiagnostics: false logLevel: Normal operatorLogLevel: Normal - - name: Should be able to pass a valid shorthand IPV6 CIDR to v6InternalMasqueradeSubnet + - name: Should be able to pass a valid shorthand IPV6 CIDR to IPV6 internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -136,7 +136,7 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv6: - v6InternalMasqueradeSubnet: "abcd:ef01::2345:6789/20" + internalMasqueradeSubnet: "abcd:ef01:2345:6789::2345:6789/20" expected: | apiVersion: operator.openshift.io/v1 kind: Network @@ -146,11 +146,11 @@ tests: gatewayConfig: routingViaHost: false ipv6: - v6InternalMasqueradeSubnet: "abcd:ef01::2345:6789/20" + internalMasqueradeSubnet: "abcd:ef01:2345:6789::2345:6789/20" disableNetworkDiagnostics: false logLevel: Normal operatorLogLevel: Normal - - name: Should not be able to pass invalid IPV6 CIDR to v6InternalMasqueradeSubnet + - name: Should not be able to pass invalid IPV6 CIDR to IPV6 internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -159,9 +159,9 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv6: - v6InternalMasqueradeSubnet: "foo" + internalMasqueradeSubnet: "foo" expectedError: "Invalid value: \"string\": subnet must be in the range /0 to /125 inclusive" - - name: Should not be able to add an IP address with the incorrect number of octets to v6InternalMasqueradeSubnet + - name: Should not be able to add an IP address with the more than 8 octets to IPV6 internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -170,9 +170,9 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv6: - v6InternalMasqueradeSubnet: abcd:ef01:2345:6789:abcd:ef01:2345:6789:abcd/125 - expectedError: "Invalid value: \"string\": a valid IPv6 address must contain at most 8 segments, or at most 6 segments for a dual address" - - name: Should not be able to add a dual IP address with the incorrect number of octets to v6InternalMasqueradeSubnet + internalMasqueradeSubnet: abcd:ef01:2345:6789:abcd:ef01:2345:6789:abcd/125 + expectedError: "Invalid value: \"string\": a valid IPv6 address must contain 8 segments unless elided (::), in which case it must contain at most 6 non-empty segments" + - name: Should not be able to add a dual IP address to IPV6 internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -181,9 +181,9 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv6: - v6InternalMasqueradeSubnet: abcd:ef01:2345:6789:abcd:ef01:2345:1.2.3.4/125 - expectedError: "Invalid value: \"string\": a valid IPv6 address must contain at most 8 segments, or at most 6 segments for a dual address" - - name: Should be able to pass a double shorthand IPV6 CIDR to v6InternalMasqueradeSubnet + internalMasqueradeSubnet: abcd:ef01:2345:6789:abcd:ef01:2345:1.2.3.4/125 + expectedError: "Invalid value: \"string\": IPv6 dual addresses are not permitted, value should not contain `.` characters" + - name: Should be able to pass a double elided IPV6 CIDR to IPV6 internalMasqueradeSubnet initial: | apiVersion: operator.openshift.io/v1 kind: Network @@ -192,5 +192,39 @@ tests: ovnKubernetesConfig: gatewayConfig: ipv6: - v6InternalMasqueradeSubnet: "abcd::ef01::2345:6789/20" - expectedError: "Invalid value: \"string\": IPv6 addresses must contain at most one '::' and may only be shortened once" \ No newline at end of file + internalMasqueradeSubnet: "abcd::ef01::2345:6789/20" + expectedError: "Invalid value: \"string\": IPv6 addresses must contain at most one '::' and may only be shortened once" + - name: "Should not be able to pass a complete IPV6 CIDR with a :: expander to v6InternalMasqueradeSubnet" + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv6: + internalMasqueradeSubnet: "abcd:ef01:2345:6789::abcd:ef01:2345:6789/125" + expectedError: "Invalid value: \"string\": a valid IPv6 address must contain 8 segments unless elided (::), in which case it must contain at most 6 non-empty segments" + - name: Should not be able to pass a IPV6 CIDR without enough segments to v6InternalMasqueradeSubnet" + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv6: + internalMasqueradeSubnet: "abcd:ef01:2345:6789:abcd:ef01:2345/125" + expectedError: "Invalid value: \"string\": a valid IPv6 address must contain 8 segments unless elided (::), in which case it must contain at most 6 non-empty segments" + - name: "Should not be able to pass an elided IPV6 CIDR with only a single empty segment to IPV6 internalMasqueradeSubnet" + initial: | + apiVersion: operator.openshift.io/v1 + kind: Network + spec: + defaultNetwork: + ovnKubernetesConfig: + gatewayConfig: + ipv6: + internalMasqueradeSubnet: "abcd:ef01:2345:6789:abcd:ef01:2345::/125" + expectedError: "Invalid value: \"string\": a valid IPv6 address must contain 8 segments unless elided (::), in which case it must contain at most 6 non-empty segments" + \ No newline at end of file diff --git a/operator/v1/types_network.go b/operator/v1/types_network.go index e2316a86a2e..17fbbed0dc0 100644 --- a/operator/v1/types_network.go +++ b/operator/v1/types_network.go @@ -507,18 +507,19 @@ type GatewayConfig struct { // The supported values are "Restricted" and "Global". // +optional IPForwarding IPForwardingMode `json:"ipForwarding,omitempty"` - // ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the defualt + // ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the default // configuration is used. Check individual members fields within ipv4 for details of default values. // +optional - IPv4 *IPv4GatewayConfig `json:"ipv4,omitempty"` - // ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the defualt + IPv4 IPv4GatewayConfig `json:"ipv4,omitempty"` + // ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the default // configuration is used. Check individual members fields within ipv6 for details of default values. // +optional - IPv6 *IPv6GatewayConfig `json:"ipv6,omitempty"` + IPv6 IPv6GatewayConfig `json:"ipv6,omitempty"` } +// IPV4GatewayConfig holds the configuration paramaters for IPV4 connections in the GatewayConfig for OVN-Kubernetes type IPv4GatewayConfig struct { - // v4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by + // internalMasqueradeSubnet contains the masquerade addresses in IPV4 CIDR format used internally by // ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these // addresses, as well as the shared gateway bridge interface. The values can be changed after // installation. The subnet chosen should not overlap with other networks specified for @@ -526,6 +527,7 @@ type IPv4GatewayConfig struct { // be large enough to accommodate 6 IPs (maximum prefix length /29). // When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. // The current default subnet is 169.254.169.0/29 + // The value must be in proper IPV4 CIDR format // +kubebuilder:validation:MaxLength=18 // +kubebuilder:validation:XValidation:rule="self.indexOf('/') == self.lastIndexOf('/')",message="CIDR format must contain exactly one '/'" // +kubebuilder:validation:XValidation:rule="[int(self.split('/')[1])].all(x, x <= 29 && x >= 0)",message="subnet must be in the range /0 to /29 inclusive" @@ -533,14 +535,12 @@ type IPv4GatewayConfig struct { // +kubebuilder:validation:XValidation:rule="[self.findAll('[0-9]+')[0]].all(x, x != '0' && int(x) <= 255 && !x.startsWith('0'))",message="first IP address octet must not contain leading zeros, must be greater than 0 and less or equal to 255" // +kubebuilder:validation:XValidation:rule="[self.findAll('[0-9]+')[1], self.findAll('[0-9]+')[2], self.findAll('[0-9]+')[3]].all(x, int(x) <= 255 && (x == '0' || !x.startsWith('0')))",message="IP address octets must not contain leading zeros, and must be less or equal to 255" // +optional - // + --- - // + The regex for the IPV4 CIDR range was taken from other feilds in the Openshift API - // + The value must be in IPV4 CIDR format - V4InternalMasqueradeSubnet string `json:"v4InternalMasqueradeSubnet,omitempty"` + InternalMasqueradeSubnet string `json:"internalMasqueradeSubnet,omitempty"` } +// IPV6GatewayConfig holds the configuration paramaters for IPV6 connections in the GatewayConfig for OVN-Kubernetes type IPv6GatewayConfig struct { - // v6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by + // internalMasqueradeSubnet contains the masquerade addresses in IPV6 CIDR format used internally by // ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these // addresses, as well as the shared gateway bridge interface. The values can be changed after // installation. The subnet chosen should not overlap with other networks specified for @@ -548,10 +548,11 @@ type IPv6GatewayConfig struct { // be large enough to accommodate 6 IPs (maximum prefix length /125). // When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. // The current default subnet is fd69::/125 + // Note that IPV6 dual addresses are not permitted // +kubebuilder:validation:XValidation:rule="self.indexOf('/') == self.lastIndexOf('/')",message="CIDR format must contain exactly one '/'" // +kubebuilder:validation:XValidation:rule="self.split('/').size() == 2 && [int(self.split('/')[1])].all(x, x <= 125 && x >= 0)",message="subnet must be in the range /0 to /125 inclusive" // +kubebuilder:validation:XValidation:rule="self.indexOf('::') == self.lastIndexOf('::')",message="IPv6 addresses must contain at most one '::' and may only be shortened once" - // +kubebuilder:validation:XValidation:rule="self.contains('.') ? self.split('/')[0].split(':').size() <= 6 : self.split('/')[0].split(':').size() <= 8",message="a valid IPv6 address must contain at most 8 segments, or at most 6 segments for a dual address" + // +kubebuilder:validation:XValidation:rule="self.contains('::') ? self.split('/')[0].split(':').size() <= 8 : self.split('/')[0].split(':').size() == 8",message="a valid IPv6 address must contain 8 segments unless elided (::), in which case it must contain at most 6 non-empty segments" // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=1 ? [self.split('/')[0].split(':', 8)[0]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 1" // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=2 ? [self.split('/')[0].split(':', 8)[1]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 2" // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=3 ? [self.split('/')[0].split(':', 8)[2]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 3" @@ -560,12 +561,9 @@ type IPv6GatewayConfig struct { // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=6 ? [self.split('/')[0].split(':', 8)[5]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 6" // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=7 ? [self.split('/')[0].split(':', 8)[6]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 7" // +kubebuilder:validation:XValidation:rule="self.split('/')[0].split(':').size() >=8 ? [self.split('/')[0].split(':', 8)[7]].all(x, x == '' || x.matches('[0-9A-Fa-f]{1,4}')) : true",message="each segment of an IPv6 address must be a hexadecimal number between 0 and FFFF, failed on segment 8" + // +kubebuilder:validation:XValidation:rule="!self.contains('.')",message="IPv6 dual addresses are not permitted, value should not contain `.` characters" // +optional - // + --- - // + The regex for the IPV6 CIDR range was taken from - // + https://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses-cidr-ranges-and-hostnames/ - // + The value must be in IPV6 CIDR format - V6InternalMasqueradeSubnet string `json:"v6InternalMasqueradeSubnet,omitempty"` + InternalMasqueradeSubnet string `json:"internalMasqueradeSubnet,omitempty"` } type ExportNetworkFlows struct { diff --git a/operator/v1/zz_generated.deepcopy.go b/operator/v1/zz_generated.deepcopy.go index 5692e4a6a3b..a0f4c1a8975 100644 --- a/operator/v1/zz_generated.deepcopy.go +++ b/operator/v1/zz_generated.deepcopy.go @@ -1533,16 +1533,8 @@ func (in *GCPLoadBalancerParameters) DeepCopy() *GCPLoadBalancerParameters { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GatewayConfig) DeepCopyInto(out *GatewayConfig) { *out = *in - if in.IPv4 != nil { - in, out := &in.IPv4, &out.IPv4 - *out = new(IPv4GatewayConfig) - **out = **in - } - if in.IPv6 != nil { - in, out := &in.IPv6, &out.IPv6 - *out = new(IPv6GatewayConfig) - **out = **in - } + out.IPv4 = in.IPv4 + out.IPv6 = in.IPv6 return } @@ -3258,7 +3250,7 @@ func (in *OVNKubernetesConfig) DeepCopyInto(out *OVNKubernetesConfig) { if in.GatewayConfig != nil { in, out := &in.GatewayConfig, &out.GatewayConfig *out = new(GatewayConfig) - (*in).DeepCopyInto(*out) + **out = **in } in.EgressIPConfig.DeepCopyInto(&out.EgressIPConfig) return diff --git a/operator/v1/zz_generated.swagger_doc_generated.go b/operator/v1/zz_generated.swagger_doc_generated.go index 480f8a3037d..f94102b4c8a 100644 --- a/operator/v1/zz_generated.swagger_doc_generated.go +++ b/operator/v1/zz_generated.swagger_doc_generated.go @@ -1301,8 +1301,8 @@ var map_GatewayConfig = map[string]string{ "": "GatewayConfig holds node gateway-related parsed config file parameters and command-line overrides", "routingViaHost": "RoutingViaHost allows pod egress traffic to exit via the ovn-k8s-mp0 management port into the host before sending it out. If this is not set, traffic will always egress directly from OVN to outside without touching the host stack. Setting this to true means hardware offload will not be supported. Default is false if GatewayConfig is specified.", "ipForwarding": "IPForwarding controls IP forwarding for all traffic on OVN-Kubernetes managed interfaces (such as br-ex). By default this is set to Restricted, and Kubernetes related traffic is still forwarded appropriately, but other IP traffic will not be routed by the OCP node. If there is a desire to allow the host to forward traffic across OVN-Kubernetes managed interfaces, then set this field to \"Global\". The supported values are \"Restricted\" and \"Global\".", - "ipv4": "ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv4 for details of default values.", - "ipv6": "ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the defualt configuration is used. Check individual members fields within ipv6 for details of default values.", + "ipv4": "ipv4 allows users to configure IP settings for IPv4 connections. When omitted, this means no opinion and the default configuration is used. Check individual members fields within ipv4 for details of default values.", + "ipv6": "ipv6 allows users to configure IP settings for IPv6 connections. When omitted, this means no opinion and the default configuration is used. Check individual members fields within ipv6 for details of default values.", } func (GatewayConfig) SwaggerDoc() map[string]string { @@ -1337,7 +1337,8 @@ func (IPFIXConfig) SwaggerDoc() map[string]string { } var map_IPv4GatewayConfig = map[string]string{ - "v4InternalMasqueradeSubnet": "v4InternalMasqueradeSubnet contains the v4 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is 169.254.169.0/29 ", + "": "IPV4GatewayConfig holds the configuration paramaters for IPV4 connections in the GatewayConfig for OVN-Kubernetes", + "internalMasqueradeSubnet": "internalMasqueradeSubnet contains the masquerade addresses in IPV4 CIDR format used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /29). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is 169.254.169.0/29 The value must be in proper IPV4 CIDR format", } func (IPv4GatewayConfig) SwaggerDoc() map[string]string { @@ -1345,7 +1346,8 @@ func (IPv4GatewayConfig) SwaggerDoc() map[string]string { } var map_IPv6GatewayConfig = map[string]string{ - "v6InternalMasqueradeSubnet": "v6InternalMasqueradeSubnet contains the v6 masquerade addresses used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is fd69::/125 ", + "": "IPV6GatewayConfig holds the configuration paramaters for IPV6 connections in the GatewayConfig for OVN-Kubernetes", + "internalMasqueradeSubnet": "internalMasqueradeSubnet contains the masquerade addresses in IPV6 CIDR format used internally by ovn-kubernetes to enable host to service traffic. Each host in the cluster is configured with these addresses, as well as the shared gateway bridge interface. The values can be changed after installation. The subnet chosen should not overlap with other networks specified for OVN-Kubernetes as well as other networks used on the host. Additionally the subnet must be large enough to accommodate 6 IPs (maximum prefix length /125). When omitted, this means no opinion and the platform is left to choose a reasonable default which is subject to change over time. The current default subnet is fd69::/125 Note that IPV6 dual addresses are not permitted", } func (IPv6GatewayConfig) SwaggerDoc() map[string]string {