mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
This tag of hcsshim brings in a couple welcome features/improvements. One being exposing a way to query for hns endpoint statistics (Packets received/sent etc.). This tag also contains some optimizations for querying whether a certain HCN feature is supported, which is a common workflow in kube-proxy on Windows. The first result from querying HCN is now cached so further calls can skip the hcn query as well as the version range parsing that was performed. This also gets rid of some redundant logs that used to hit everytime the version range parsing occurred. The Go-winio dep bump, and all of the ctrd deps are transitive only. Nothing new is needed/intended to be used. Signed-off-by: Daniel Canter <dcanter@microsoft.com>
144 lines
5.9 KiB
Go
144 lines
5.9 KiB
Go
package hcn
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var (
|
|
// featuresOnce handles assigning the supported features and printing the supported info to stdout only once to avoid unnecessary work
|
|
// multiple times.
|
|
featuresOnce sync.Once
|
|
featuresErr error
|
|
supportedFeatures SupportedFeatures
|
|
)
|
|
|
|
// SupportedFeatures are the features provided by the Service.
|
|
type SupportedFeatures struct {
|
|
Acl AclFeatures `json:"ACL"`
|
|
Api ApiSupport `json:"API"`
|
|
RemoteSubnet bool `json:"RemoteSubnet"`
|
|
HostRoute bool `json:"HostRoute"`
|
|
DSR bool `json:"DSR"`
|
|
Slash32EndpointPrefixes bool `json:"Slash32EndpointPrefixes"`
|
|
AclSupportForProtocol252 bool `json:"AclSupportForProtocol252"`
|
|
SessionAffinity bool `json:"SessionAffinity"`
|
|
IPv6DualStack bool `json:"IPv6DualStack"`
|
|
SetPolicy bool `json:"SetPolicy"`
|
|
VxlanPort bool `json:"VxlanPort"`
|
|
L4Proxy bool `json:"L4Proxy"` // network policy that applies VFP rules to all endpoints on the network to redirect traffic
|
|
L4WfpProxy bool `json:"L4WfpProxy"` // endpoint policy that applies WFP filters to redirect traffic to/from that endpoint
|
|
TierAcl bool `json:"TierAcl"`
|
|
}
|
|
|
|
// AclFeatures are the supported ACL possibilities.
|
|
type AclFeatures struct {
|
|
AclAddressLists bool `json:"AclAddressLists"`
|
|
AclNoHostRulePriority bool `json:"AclHostRulePriority"`
|
|
AclPortRanges bool `json:"AclPortRanges"`
|
|
AclRuleId bool `json:"AclRuleId"`
|
|
}
|
|
|
|
// ApiSupport lists the supported API versions.
|
|
type ApiSupport struct {
|
|
V1 bool `json:"V1"`
|
|
V2 bool `json:"V2"`
|
|
}
|
|
|
|
// GetCachedSupportedFeatures returns the features supported by the Service and an error if the query failed. If this has been called
|
|
// before it will return the supported features and error received from the first call. This can be used to optimize if many calls to the
|
|
// various hcn.IsXSupported methods need to be made.
|
|
func GetCachedSupportedFeatures() (SupportedFeatures, error) {
|
|
// Only query the HCN version and features supported once, instead of everytime this is invoked. The logs are useful to
|
|
// debug incidents where there's confusion on if a feature is supported on the host machine. The sync.Once helps to avoid redundant
|
|
// spam of these anytime a check needs to be made for if an HCN feature is supported. This is a common occurrence in kube-proxy
|
|
// for example.
|
|
featuresOnce.Do(func() {
|
|
supportedFeatures, featuresErr = getSupportedFeatures()
|
|
})
|
|
|
|
return supportedFeatures, featuresErr
|
|
}
|
|
|
|
// GetSupportedFeatures returns the features supported by the Service.
|
|
//
|
|
// Deprecated: Use GetCachedSupportedFeatures instead.
|
|
func GetSupportedFeatures() SupportedFeatures {
|
|
features, err := GetCachedSupportedFeatures()
|
|
if err != nil {
|
|
// Expected on pre-1803 builds, all features will be false/unsupported
|
|
logrus.WithError(err).Errorf("unable to obtain supported features")
|
|
return features
|
|
}
|
|
return features
|
|
}
|
|
|
|
func getSupportedFeatures() (SupportedFeatures, error) {
|
|
var features SupportedFeatures
|
|
globals, err := GetGlobals()
|
|
if err != nil {
|
|
// It's expected if this fails once, it should always fail. It should fail on pre 1803 builds for example.
|
|
return SupportedFeatures{}, errors.Wrap(err, "failed to query HCN version number: this is expected on pre 1803 builds.")
|
|
}
|
|
features.Acl = AclFeatures{
|
|
AclAddressLists: isFeatureSupported(globals.Version, HNSVersion1803),
|
|
AclNoHostRulePriority: isFeatureSupported(globals.Version, HNSVersion1803),
|
|
AclPortRanges: isFeatureSupported(globals.Version, HNSVersion1803),
|
|
AclRuleId: isFeatureSupported(globals.Version, HNSVersion1803),
|
|
}
|
|
|
|
features.Api = ApiSupport{
|
|
V2: isFeatureSupported(globals.Version, V2ApiSupport),
|
|
V1: true, // HNSCall is still available.
|
|
}
|
|
|
|
features.RemoteSubnet = isFeatureSupported(globals.Version, RemoteSubnetVersion)
|
|
features.HostRoute = isFeatureSupported(globals.Version, HostRouteVersion)
|
|
features.DSR = isFeatureSupported(globals.Version, DSRVersion)
|
|
features.Slash32EndpointPrefixes = isFeatureSupported(globals.Version, Slash32EndpointPrefixesVersion)
|
|
features.AclSupportForProtocol252 = isFeatureSupported(globals.Version, AclSupportForProtocol252Version)
|
|
features.SessionAffinity = isFeatureSupported(globals.Version, SessionAffinityVersion)
|
|
features.IPv6DualStack = isFeatureSupported(globals.Version, IPv6DualStackVersion)
|
|
features.SetPolicy = isFeatureSupported(globals.Version, SetPolicyVersion)
|
|
features.VxlanPort = isFeatureSupported(globals.Version, VxlanPortVersion)
|
|
features.L4Proxy = isFeatureSupported(globals.Version, L4ProxyPolicyVersion)
|
|
features.L4WfpProxy = isFeatureSupported(globals.Version, L4WfpProxyPolicyVersion)
|
|
features.TierAcl = isFeatureSupported(globals.Version, TierAclPolicyVersion)
|
|
|
|
logrus.WithFields(logrus.Fields{
|
|
"version": fmt.Sprintf("%+v", globals.Version),
|
|
"supportedFeatures": fmt.Sprintf("%+v", features),
|
|
}).Info("HCN feature check")
|
|
|
|
return features, nil
|
|
}
|
|
|
|
func isFeatureSupported(currentVersion Version, versionsSupported VersionRanges) bool {
|
|
isFeatureSupported := false
|
|
|
|
for _, versionRange := range versionsSupported {
|
|
isFeatureSupported = isFeatureSupported || isFeatureInRange(currentVersion, versionRange)
|
|
}
|
|
|
|
return isFeatureSupported
|
|
}
|
|
|
|
func isFeatureInRange(currentVersion Version, versionRange VersionRange) bool {
|
|
if currentVersion.Major < versionRange.MinVersion.Major {
|
|
return false
|
|
}
|
|
if currentVersion.Major > versionRange.MaxVersion.Major {
|
|
return false
|
|
}
|
|
if currentVersion.Major == versionRange.MinVersion.Major && currentVersion.Minor < versionRange.MinVersion.Minor {
|
|
return false
|
|
}
|
|
if currentVersion.Major == versionRange.MaxVersion.Major && currentVersion.Minor > versionRange.MaxVersion.Minor {
|
|
return false
|
|
}
|
|
return true
|
|
}
|