diff --git a/pkg/types/validation/installconfig.go b/pkg/types/validation/installconfig.go index 304df4b953f..afbcc38e6a6 100644 --- a/pkg/types/validation/installconfig.go +++ b/pkg/types/validation/installconfig.go @@ -222,6 +222,23 @@ func validateNetworkingIPVersion(n *types.Networking, p *types.Platform) field.E case p.Azure != nil && experimentalDualStackEnabled: logrus.Warnf("Using experimental Azure dual-stack support") case p.BareMetal != nil: + apiVIPIPFamily := corev1.IPv6Protocol + if net.ParseIP(p.BareMetal.APIVIP).To4() != nil { + apiVIPIPFamily = corev1.IPv4Protocol + } + + if apiVIPIPFamily != presence["machineNetwork"].Primary { + allErrs = append(allErrs, field.Invalid(field.NewPath("networking", "baremetal", "apiVIP"), p.BareMetal.APIVIP, "VIP for the API must be of the same IP family with machine network's primary IP Family for dual-stack IPv4/IPv6")) + } + + ingressVIPIPFamily := corev1.IPv6Protocol + if net.ParseIP(p.BareMetal.IngressVIP).To4() != nil { + ingressVIPIPFamily = corev1.IPv4Protocol + } + + if ingressVIPIPFamily != presence["machineNetwork"].Primary { + allErrs = append(allErrs, field.Invalid(field.NewPath("networking", "baremetal", "ingressVIP"), p.BareMetal.IngressVIP, "VIP for the Ingress must be of the same IP family with machine network's primary IP Family for dual-stack IPv4/IPv6")) + } case p.None != nil: default: allErrs = append(allErrs, field.Invalid(field.NewPath("networking"), "DualStack", "dual-stack IPv4/IPv6 is not supported for this platform, specify only one type of address")) diff --git a/pkg/types/validation/installconfig_test.go b/pkg/types/validation/installconfig_test.go index df99c1a7ec2..ca656b9a461 100644 --- a/pkg/types/validation/installconfig_test.go +++ b/pkg/types/validation/installconfig_test.go @@ -637,6 +637,19 @@ func TestValidateInstallConfig(t *testing.T) { }(), expectedError: `^platform\.baremetal\.apiVIP: Invalid value: "10\.1\.0\.5": IP expected to be in one of the machine networks: 10.0.0.0/16$`, }, + { + name: "baremetal API VIP set to an incorrect IP Family", + installConfig: func() *types.InstallConfig { + c := validInstallConfig() + c.Networking = validDualStackNetworkingConfig() + c.Platform = types.Platform{ + BareMetal: validBareMetalPlatform(), + } + c.Platform.BareMetal.APIVIP = "ffd0::" + return c + }(), + expectedError: `networking.baremetal.apiVIP: Invalid value: "ffd0::": VIP for the API must be of the same IP family with machine network's primary IP Family for dual-stack IPv4/IPv6`, + }, { name: "baremetal Ingress VIP not an IP", installConfig: func() *types.InstallConfig { @@ -649,6 +662,19 @@ func TestValidateInstallConfig(t *testing.T) { }(), expectedError: `^\[platform\.baremetal\.ingressVIP: Invalid value: "test": "test" is not a valid IP, platform\.baremetal\.ingressVIP: Invalid value: "test": IP expected to be in one of the machine networks: 10.0.0.0/16]$`, }, + { + name: "baremetal Ingress VIP set to an incorrect IP Family", + installConfig: func() *types.InstallConfig { + c := validInstallConfig() + c.Networking = validDualStackNetworkingConfig() + c.Platform = types.Platform{ + BareMetal: validBareMetalPlatform(), + } + c.Platform.BareMetal.IngressVIP = "ffd0::" + return c + }(), + expectedError: `networking.baremetal.ingressVIP: Invalid value: "ffd0::": VIP for the Ingress must be of the same IP family with machine network's primary IP Family for dual-stack IPv4/IPv6`, + }, { name: "baremetal Ingress VIP set to an incorrect value", installConfig: func() *types.InstallConfig {