istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/networking/core/cluster_cache.go (about) 1 // Copyright Istio Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package core 16 17 import ( 18 "strconv" 19 "strings" 20 21 core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" 22 23 "istio.io/istio/pilot/pkg/model" 24 "istio.io/istio/pilot/pkg/networking/util" 25 "istio.io/istio/pilot/pkg/xds/endpoints" 26 "istio.io/istio/pkg/config/schema/kind" 27 "istio.io/istio/pkg/util/hash" 28 ) 29 30 var ( 31 Separator = []byte{'~'} 32 Slash = []byte{'/'} 33 ) 34 35 // clusterCache includes the variables that can influence a Cluster Configuration. 36 // Implements XdsCacheEntry interface. 37 type clusterCache struct { 38 clusterName string 39 40 // proxy related cache fields 41 proxyVersion string // will be matched by envoyfilter patches 42 locality *core.Locality // identifies the locality the cluster is generated for 43 proxyClusterID string // identifies the kubernetes cluster a proxy is in 44 proxySidecar bool // identifies if this proxy is a Sidecar 45 hbone bool 46 proxyView model.ProxyView 47 metadataCerts *metadataCerts // metadata certificates of proxy 48 endpointBuilder *endpoints.EndpointBuilder 49 50 // service attributes 51 http2 bool // http2 identifies if the cluster is for an http2 service 52 downstreamAuto bool 53 supportsIPv4 bool 54 55 // dependent configs 56 service *model.Service 57 destinationRule *model.ConsolidatedDestRule 58 envoyFilterKeys []string 59 peerAuthVersion string // identifies the versions of all peer authentications 60 serviceAccounts []string // contains all the service accounts associated with the service 61 } 62 63 func (t *clusterCache) Type() string { 64 return model.CDSType 65 } 66 67 func (t *clusterCache) Key() any { 68 // nolint: gosec 69 // Not security sensitive code 70 h := hash.New() 71 h.WriteString(t.clusterName) 72 h.Write(Separator) 73 h.WriteString(t.proxyVersion) 74 h.Write(Separator) 75 h.WriteString(util.LocalityToString(t.locality)) 76 h.Write(Separator) 77 h.WriteString(t.proxyClusterID) 78 h.Write(Separator) 79 h.WriteString(strconv.FormatBool(t.proxySidecar)) 80 h.Write(Separator) 81 h.WriteString(strconv.FormatBool(t.http2)) 82 h.Write(Separator) 83 h.WriteString(strconv.FormatBool(t.downstreamAuto)) 84 h.Write(Separator) 85 h.WriteString(strconv.FormatBool(t.supportsIPv4)) 86 h.Write(Separator) 87 h.WriteString(strconv.FormatBool(t.hbone)) 88 h.Write(Separator) 89 90 if t.proxyView != nil { 91 h.WriteString(t.proxyView.String()) 92 } 93 h.Write(Separator) 94 95 if t.metadataCerts != nil { 96 h.WriteString(t.metadataCerts.String()) 97 } 98 h.Write(Separator) 99 100 if t.service != nil { 101 h.WriteString(string(t.service.Hostname)) 102 h.Write(Slash) 103 h.WriteString(t.service.Attributes.Namespace) 104 } 105 h.Write(Separator) 106 107 for _, dr := range t.destinationRule.GetFrom() { 108 h.WriteString(dr.Name) 109 h.Write(Slash) 110 h.WriteString(dr.Namespace) 111 } 112 h.Write(Separator) 113 114 for _, efk := range t.envoyFilterKeys { 115 h.WriteString(efk) 116 h.Write(Separator) 117 } 118 h.Write(Separator) 119 120 h.WriteString(t.peerAuthVersion) 121 h.Write(Separator) 122 123 for _, sa := range t.serviceAccounts { 124 h.WriteString(sa) 125 h.Write(Separator) 126 } 127 h.Write(Separator) 128 129 if t.endpointBuilder != nil { 130 t.endpointBuilder.WriteHash(h) 131 } 132 133 return h.Sum64() 134 } 135 136 func (t *clusterCache) DependentConfigs() []model.ConfigHash { 137 drs := t.destinationRule.GetFrom() 138 configs := make([]model.ConfigHash, 0, len(drs)+1+len(t.envoyFilterKeys)) 139 if t.destinationRule != nil { 140 for _, dr := range drs { 141 configs = append(configs, model.ConfigKey{Kind: kind.DestinationRule, Name: dr.Name, Namespace: dr.Namespace}.HashCode()) 142 } 143 } 144 if t.service != nil { 145 configs = append(configs, model.ConfigKey{Kind: kind.ServiceEntry, Name: string(t.service.Hostname), Namespace: t.service.Attributes.Namespace}.HashCode()) 146 } 147 for _, efKey := range t.envoyFilterKeys { 148 items := strings.Split(efKey, "/") 149 configs = append(configs, model.ConfigKey{Kind: kind.EnvoyFilter, Name: items[1], Namespace: items[0]}.HashCode()) 150 } 151 152 // For now, this matches EndpointBuilder's DependentConfigs. No need to duplicate them. 153 154 return configs 155 } 156 157 func (t *clusterCache) Cacheable() bool { 158 return true 159 } 160 161 // cacheStats keeps track of cache usage stats. 162 type cacheStats struct { 163 hits, miss int 164 } 165 166 func (c cacheStats) empty() bool { 167 return c.hits == 0 && c.miss == 0 168 } 169 170 func (c cacheStats) merge(other cacheStats) cacheStats { 171 return cacheStats{ 172 hits: c.hits + other.hits, 173 miss: c.miss + other.miss, 174 } 175 } 176 177 func buildClusterKey(service *model.Service, port *model.Port, cb *ClusterBuilder, proxy *model.Proxy, efKeys []string) clusterCache { 178 clusterName := model.BuildSubsetKey(model.TrafficDirectionOutbound, "", service.Hostname, port.Port) 179 dr := proxy.SidecarScope.DestinationRule(model.TrafficDirectionOutbound, proxy, service.Hostname) 180 var eb *endpoints.EndpointBuilder 181 if service.Resolution == model.DNSLB || service.Resolution == model.DNSRoundRobinLB { 182 eb = endpoints.NewCDSEndpointBuilder( 183 proxy, 184 cb.req.Push, 185 clusterName, 186 model.TrafficDirectionOutbound, "", service.Hostname, port.Port, 187 service, dr, 188 ) 189 } 190 return clusterCache{ 191 clusterName: clusterName, 192 proxyVersion: cb.proxyVersion, 193 locality: cb.locality, 194 proxyClusterID: cb.clusterID, 195 proxySidecar: cb.sidecarProxy(), 196 proxyView: cb.proxyView, 197 hbone: cb.sendHbone, 198 http2: port.Protocol.IsHTTP2(), 199 downstreamAuto: cb.sidecarProxy() && port.Protocol.IsUnsupported(), 200 supportsIPv4: cb.supportsIPv4, 201 service: service, 202 destinationRule: dr, 203 envoyFilterKeys: efKeys, 204 metadataCerts: cb.metadataCerts, 205 peerAuthVersion: cb.req.Push.AuthnPolicies.GetVersion(), 206 serviceAccounts: cb.req.Push.ServiceAccounts(service.Hostname, service.Attributes.Namespace), 207 endpointBuilder: eb, 208 } 209 }