mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-22 18:37:15 +00:00
Only use dualstack if the node and config supports it
This commit is contained in:
@@ -31,13 +31,14 @@ import (
|
||||
|
||||
"github.com/Microsoft/hcsshim"
|
||||
"github.com/Microsoft/hcsshim/hcn"
|
||||
discovery "k8s.io/api/discovery/v1"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
discovery "k8s.io/api/discovery/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
apiutil "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/tools/events"
|
||||
@@ -137,6 +138,101 @@ type remoteSubnetInfo struct {
|
||||
|
||||
const NETWORK_TYPE_OVERLAY = "overlay"
|
||||
|
||||
func newHostNetworkService() (HostNetworkService, hcn.SupportedFeatures) {
|
||||
var hns HostNetworkService
|
||||
hns = hnsV1{}
|
||||
supportedFeatures := hcn.GetSupportedFeatures()
|
||||
if supportedFeatures.Api.V2 {
|
||||
hns = hnsV2{}
|
||||
}
|
||||
|
||||
return hns, supportedFeatures
|
||||
}
|
||||
|
||||
func getNetworkName(hnsNetworkName string) (string, error) {
|
||||
if len(hnsNetworkName) == 0 {
|
||||
klog.V(3).InfoS("network-name flag not set. Checking environment variable")
|
||||
hnsNetworkName = os.Getenv("KUBE_NETWORK")
|
||||
if len(hnsNetworkName) == 0 {
|
||||
return "", fmt.Errorf("Environment variable KUBE_NETWORK and network-flag not initialized")
|
||||
}
|
||||
}
|
||||
return hnsNetworkName, nil
|
||||
}
|
||||
|
||||
func getNetworkInfo(hns HostNetworkService, hnsNetworkName string) (*hnsNetworkInfo, error) {
|
||||
hnsNetworkInfo, err := hns.getNetworkByName(hnsNetworkName)
|
||||
for err != nil {
|
||||
klog.ErrorS(err, "Unable to find HNS Network specified. Please check network name and CNI deployment", "hnsNetworkName", hnsNetworkName)
|
||||
time.Sleep(1 * time.Second)
|
||||
hnsNetworkInfo, err = hns.getNetworkByName(hnsNetworkName)
|
||||
}
|
||||
return hnsNetworkInfo, err
|
||||
}
|
||||
|
||||
func isOverlay(hnsNetworkInfo *hnsNetworkInfo) bool {
|
||||
return strings.EqualFold(hnsNetworkInfo.networkType, NETWORK_TYPE_OVERLAY)
|
||||
}
|
||||
|
||||
// StackCompatTester tests whether the required kernel and network are dualstack capable
|
||||
type StackCompatTester interface {
|
||||
DualStackCompatible(networkName string) bool
|
||||
}
|
||||
|
||||
type DualStackCompatTester struct{}
|
||||
|
||||
func (t DualStackCompatTester) DualStackCompatible(networkName string) bool {
|
||||
dualStackFeatureEnabled := utilfeature.DefaultFeatureGate.Enabled(kubefeatures.IPv6DualStack)
|
||||
if !dualStackFeatureEnabled {
|
||||
return false
|
||||
}
|
||||
|
||||
globals, err := hcn.GetGlobals()
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "Unable to determine networking stack version. Falling back to single-stack")
|
||||
return false
|
||||
}
|
||||
|
||||
if !kernelSupportsDualstack(globals.Version) {
|
||||
klog.InfoS("This version of Windows does not support dual-stack. Falling back to single-stack")
|
||||
return false
|
||||
}
|
||||
|
||||
// check if network is using overlay
|
||||
hns, _ := newHostNetworkService()
|
||||
networkName, err = getNetworkName(networkName)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to determine dual-stack status %v. Falling back to single-stack")
|
||||
return false
|
||||
}
|
||||
networkInfo, err := getNetworkInfo(hns, networkName)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to determine dual-stack status %v. Falling back to single-stack")
|
||||
return false
|
||||
}
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.WinOverlay) && isOverlay(networkInfo) {
|
||||
// Overlay (VXLAN) networks on Windows do not support dual-stack networking today
|
||||
klog.InfoS("Winoverlay does not support dual-stack. Falling back to single-stack")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// The hcsshim version logic has a bug that did not calculate the versioning of DualStack correctly.
|
||||
// DualStack is supported in WS 2004+ (10.0.19041+) where HCN component version is 11.10+
|
||||
// https://github.com/microsoft/hcsshim/pull/1003#issuecomment-827930358
|
||||
func kernelSupportsDualstack(currentVersion hcn.Version) bool {
|
||||
hnsVersion := fmt.Sprintf("%d.%d.0", currentVersion.Major, currentVersion.Minor)
|
||||
v, err := version.ParseSemantic(hnsVersion)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return v.AtLeast(version.MustParseSemantic("11.10.0"))
|
||||
}
|
||||
|
||||
func Log(v interface{}, message string, level klog.Level) {
|
||||
klog.V(level).InfoS("%s", message, "spewConfig", spewSdump(v))
|
||||
}
|
||||
@@ -546,36 +642,24 @@ func NewProxier(
|
||||
}
|
||||
|
||||
serviceHealthServer := healthcheck.NewServiceHealthServer(hostname, recorder)
|
||||
var hns HostNetworkService
|
||||
hns = hnsV1{}
|
||||
supportedFeatures := hcn.GetSupportedFeatures()
|
||||
if supportedFeatures.Api.V2 {
|
||||
hns = hnsV2{}
|
||||
}
|
||||
|
||||
hnsNetworkName := config.NetworkName
|
||||
if len(hnsNetworkName) == 0 {
|
||||
klog.V(3).InfoS("network-name flag not set. Checking environment variable")
|
||||
hnsNetworkName = os.Getenv("KUBE_NETWORK")
|
||||
if len(hnsNetworkName) == 0 {
|
||||
return nil, fmt.Errorf("Environment variable KUBE_NETWORK and network-flag not initialized")
|
||||
}
|
||||
hns, supportedFeatures := newHostNetworkService()
|
||||
hnsNetworkName, err := getNetworkName(config.NetworkName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
klog.V(3).InfoS("Cleaning up old HNS policy lists")
|
||||
deleteAllHnsLoadBalancerPolicy()
|
||||
|
||||
// Get HNS network information
|
||||
hnsNetworkInfo, err := hns.getNetworkByName(hnsNetworkName)
|
||||
for err != nil {
|
||||
klog.ErrorS(err, "Unable to find HNS Network specified. Please check network name and CNI deployment", "hnsNetworkName", hnsNetworkName)
|
||||
time.Sleep(1 * time.Second)
|
||||
hnsNetworkInfo, err = hns.getNetworkByName(hnsNetworkName)
|
||||
hnsNetworkInfo, err := getNetworkInfo(hns, hnsNetworkName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Network could have been detected before Remote Subnet Routes are applied or ManagementIP is updated
|
||||
// Sleep and update the network to include new information
|
||||
if strings.EqualFold(hnsNetworkInfo.networkType, NETWORK_TYPE_OVERLAY) {
|
||||
if isOverlay(hnsNetworkInfo) {
|
||||
time.Sleep(10 * time.Second)
|
||||
hnsNetworkInfo, err = hns.getNetworkByName(hnsNetworkName)
|
||||
if err != nil {
|
||||
@@ -595,7 +679,7 @@ func NewProxier(
|
||||
|
||||
var sourceVip string
|
||||
var hostMac string
|
||||
if strings.EqualFold(hnsNetworkInfo.networkType, NETWORK_TYPE_OVERLAY) {
|
||||
if isOverlay(hnsNetworkInfo) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(kubefeatures.WinOverlay) {
|
||||
return nil, fmt.Errorf("WinOverlay feature gate not enabled")
|
||||
}
|
||||
@@ -608,6 +692,15 @@ func NewProxier(
|
||||
return nil, fmt.Errorf("source-vip flag not set")
|
||||
}
|
||||
|
||||
if nodeIP.IsUnspecified() {
|
||||
// attempt to get the correct ip address
|
||||
klog.V(2).InfoS("node ip was unspecified. Attempting to find node ip")
|
||||
nodeIP, err = apiutil.ResolveBindAddress(nodeIP)
|
||||
if err != nil {
|
||||
klog.InfoS("failed to find an ip. You may need set the --bind-address flag", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
interfaces, _ := net.Interfaces() //TODO create interfaces
|
||||
for _, inter := range interfaces {
|
||||
addresses, _ := inter.Addrs()
|
||||
|
@@ -25,6 +25,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Microsoft/hcsshim/hcn"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
discovery "k8s.io/api/discovery/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -928,3 +929,54 @@ func makeTestEndpointSlice(namespace, name string, sliceNum int, epsFunc func(*d
|
||||
epsFunc(eps)
|
||||
return eps
|
||||
}
|
||||
|
||||
func Test_kernelSupportsDualstack(t *testing.T) {
|
||||
tests := []struct {
|
||||
currentVersion hcn.Version
|
||||
name string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
hcn.Version{Major: 10, Minor: 10},
|
||||
"Less than minimal should not be supported",
|
||||
false,
|
||||
},
|
||||
{
|
||||
hcn.Version{Major: 9, Minor: 11},
|
||||
"Less than minimal should not be supported",
|
||||
false,
|
||||
},
|
||||
{
|
||||
hcn.Version{Major: 11, Minor: 1},
|
||||
"Less than minimal should not be supported",
|
||||
false,
|
||||
},
|
||||
{
|
||||
hcn.Version{Major: 11, Minor: 10},
|
||||
"Current version should be supported",
|
||||
true,
|
||||
},
|
||||
{
|
||||
hcn.Version{Major: 11, Minor: 11},
|
||||
"Greater than minimal version should be supported",
|
||||
true,
|
||||
},
|
||||
{
|
||||
hcn.Version{Major: 12, Minor: 1},
|
||||
"Greater than minimal version should be supported",
|
||||
true,
|
||||
},
|
||||
{
|
||||
hcn.Version{Major: 12, Minor: 12},
|
||||
"Greater than minimal should be supported",
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := kernelSupportsDualstack(tt.currentVersion); got != tt.want {
|
||||
t.Errorf("kernelSupportsDualstack on version %v: got %v, want %v", tt.currentVersion, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user