hcnsupport.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. //go:build windows
  2. package hcn
  3. import (
  4. "sync"
  5. "github.com/pkg/errors"
  6. "github.com/sirupsen/logrus"
  7. "github.com/Microsoft/hcsshim/internal/log"
  8. )
  9. var (
  10. // featuresOnce handles assigning the supported features and printing the supported info to stdout only once to avoid unnecessary work
  11. // multiple times.
  12. featuresOnce sync.Once
  13. featuresErr error
  14. supportedFeatures SupportedFeatures
  15. )
  16. // SupportedFeatures are the features provided by the Service.
  17. type SupportedFeatures struct {
  18. Acl AclFeatures `json:"ACL"`
  19. Api ApiSupport `json:"API"`
  20. RemoteSubnet bool `json:"RemoteSubnet"`
  21. HostRoute bool `json:"HostRoute"`
  22. DSR bool `json:"DSR"`
  23. Slash32EndpointPrefixes bool `json:"Slash32EndpointPrefixes"`
  24. AclSupportForProtocol252 bool `json:"AclSupportForProtocol252"`
  25. SessionAffinity bool `json:"SessionAffinity"`
  26. IPv6DualStack bool `json:"IPv6DualStack"`
  27. SetPolicy bool `json:"SetPolicy"`
  28. VxlanPort bool `json:"VxlanPort"`
  29. L4Proxy bool `json:"L4Proxy"` // network policy that applies VFP rules to all endpoints on the network to redirect traffic
  30. L4WfpProxy bool `json:"L4WfpProxy"` // endpoint policy that applies WFP filters to redirect traffic to/from that endpoint
  31. TierAcl bool `json:"TierAcl"`
  32. NetworkACL bool `json:"NetworkACL"`
  33. NestedIpSet bool `json:"NestedIpSet"`
  34. }
  35. // AclFeatures are the supported ACL possibilities.
  36. type AclFeatures struct {
  37. AclAddressLists bool `json:"AclAddressLists"`
  38. AclNoHostRulePriority bool `json:"AclHostRulePriority"`
  39. AclPortRanges bool `json:"AclPortRanges"`
  40. AclRuleId bool `json:"AclRuleId"`
  41. }
  42. // ApiSupport lists the supported API versions.
  43. type ApiSupport struct {
  44. V1 bool `json:"V1"`
  45. V2 bool `json:"V2"`
  46. }
  47. // GetCachedSupportedFeatures returns the features supported by the Service and an error if the query failed. If this has been called
  48. // 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
  49. // various hcn.IsXSupported methods need to be made.
  50. func GetCachedSupportedFeatures() (SupportedFeatures, error) {
  51. // Only query the HCN version and features supported once, instead of everytime this is invoked. The logs are useful to
  52. // debug incidents where there's confusion on if a feature is supported on the host machine. The sync.Once helps to avoid redundant
  53. // 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
  54. // for example.
  55. featuresOnce.Do(func() {
  56. supportedFeatures, featuresErr = getSupportedFeatures()
  57. })
  58. return supportedFeatures, featuresErr
  59. }
  60. // GetSupportedFeatures returns the features supported by the Service.
  61. //
  62. // Deprecated: Use GetCachedSupportedFeatures instead.
  63. func GetSupportedFeatures() SupportedFeatures {
  64. features, err := GetCachedSupportedFeatures()
  65. if err != nil {
  66. // Expected on pre-1803 builds, all features will be false/unsupported
  67. logrus.WithError(err).Errorf("unable to obtain supported features")
  68. return features
  69. }
  70. return features
  71. }
  72. func getSupportedFeatures() (SupportedFeatures, error) {
  73. var features SupportedFeatures
  74. globals, err := GetGlobals()
  75. if err != nil {
  76. // It's expected if this fails once, it should always fail. It should fail on pre 1803 builds for example.
  77. return SupportedFeatures{}, errors.Wrap(err, "failed to query HCN version number: this is expected on pre 1803 builds.")
  78. }
  79. features.Acl = AclFeatures{
  80. AclAddressLists: isFeatureSupported(globals.Version, HNSVersion1803),
  81. AclNoHostRulePriority: isFeatureSupported(globals.Version, HNSVersion1803),
  82. AclPortRanges: isFeatureSupported(globals.Version, HNSVersion1803),
  83. AclRuleId: isFeatureSupported(globals.Version, HNSVersion1803),
  84. }
  85. features.Api = ApiSupport{
  86. V2: isFeatureSupported(globals.Version, V2ApiSupport),
  87. V1: true, // HNSCall is still available.
  88. }
  89. features.RemoteSubnet = isFeatureSupported(globals.Version, RemoteSubnetVersion)
  90. features.HostRoute = isFeatureSupported(globals.Version, HostRouteVersion)
  91. features.DSR = isFeatureSupported(globals.Version, DSRVersion)
  92. features.Slash32EndpointPrefixes = isFeatureSupported(globals.Version, Slash32EndpointPrefixesVersion)
  93. features.AclSupportForProtocol252 = isFeatureSupported(globals.Version, AclSupportForProtocol252Version)
  94. features.SessionAffinity = isFeatureSupported(globals.Version, SessionAffinityVersion)
  95. features.IPv6DualStack = isFeatureSupported(globals.Version, IPv6DualStackVersion)
  96. features.SetPolicy = isFeatureSupported(globals.Version, SetPolicyVersion)
  97. features.VxlanPort = isFeatureSupported(globals.Version, VxlanPortVersion)
  98. features.L4Proxy = isFeatureSupported(globals.Version, L4ProxyPolicyVersion)
  99. features.L4WfpProxy = isFeatureSupported(globals.Version, L4WfpProxyPolicyVersion)
  100. features.TierAcl = isFeatureSupported(globals.Version, TierAclPolicyVersion)
  101. features.NetworkACL = isFeatureSupported(globals.Version, NetworkACLPolicyVersion)
  102. features.NestedIpSet = isFeatureSupported(globals.Version, NestedIpSetVersion)
  103. log.L.WithFields(logrus.Fields{
  104. "version": globals.Version,
  105. "supportedFeatures": features,
  106. }).Info("HCN feature check")
  107. return features, nil
  108. }
  109. func isFeatureSupported(currentVersion Version, versionsSupported VersionRanges) bool {
  110. isFeatureSupported := false
  111. for _, versionRange := range versionsSupported {
  112. isFeatureSupported = isFeatureSupported || isFeatureInRange(currentVersion, versionRange)
  113. }
  114. return isFeatureSupported
  115. }
  116. func isFeatureInRange(currentVersion Version, versionRange VersionRange) bool {
  117. if currentVersion.Major < versionRange.MinVersion.Major {
  118. return false
  119. }
  120. if currentVersion.Major > versionRange.MaxVersion.Major {
  121. return false
  122. }
  123. if currentVersion.Major == versionRange.MinVersion.Major && currentVersion.Minor < versionRange.MinVersion.Minor {
  124. return false
  125. }
  126. if currentVersion.Major == versionRange.MaxVersion.Major && currentVersion.Minor > versionRange.MaxVersion.Minor {
  127. return false
  128. }
  129. return true
  130. }