istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/networking/core/route/route_cache.go (about) 1 // Copyright Istio Authors 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 route 16 17 import ( 18 "fmt" 19 "math/big" 20 "strconv" 21 "strings" 22 23 networking "istio.io/api/networking/v1alpha3" 24 "istio.io/istio/pilot/pkg/model" 25 "istio.io/istio/pkg/config" 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 // Cache includes the variables that can influence a Route Configuration. 36 // Implements XdsCacheEntry interface. 37 type Cache struct { 38 RouteName string 39 40 ProxyVersion string 41 // proxy cluster ID 42 ClusterID string 43 // proxy dns domain 44 DNSDomain string 45 // DNSCapture indicates whether the workload has enabled dns capture 46 DNSCapture bool 47 // DNSAutoAllocate indicates whether the workload should have auto allocated addresses for ServiceEntry 48 // This allows resolving ServiceEntries, which is especially useful for distinguishing TCP traffic 49 // This depends on DNSCapture. 50 DNSAutoAllocate bool 51 // AllowAny indicates if the proxy should allow all outbound traffic or only known registries 52 AllowAny bool 53 54 ListenerPort int 55 Services []*model.Service 56 VirtualServices []config.Config 57 DelegateVirtualServices []model.ConfigHash 58 DestinationRules []*model.ConsolidatedDestRule 59 EnvoyFilterKeys []string 60 } 61 62 func (r *Cache) Type() string { 63 return model.RDSType 64 } 65 66 func (r *Cache) Cacheable() bool { 67 if r == nil { 68 return false 69 } 70 if r.ListenerPort == 0 { 71 return false 72 } 73 74 for _, config := range r.VirtualServices { 75 vs := config.Spec.(*networking.VirtualService) 76 for _, httpRoute := range vs.Http { 77 for _, match := range httpRoute.Match { 78 // if vs has source match, not cacheable 79 if len(match.SourceLabels) > 0 || match.SourceNamespace != "" { 80 return false 81 } 82 } 83 } 84 } 85 86 return true 87 } 88 89 func extractNamespaceForKubernetesService(hostname string) (string, error) { 90 ih := strings.Index(hostname, ".svc.") 91 if ih < 0 { 92 return "", fmt.Errorf("hostname is a not a Kubernetes name, missing .svc: %v", hostname) 93 } 94 nsI := strings.Index(hostname, ".") 95 if nsI+1 >= len(hostname) || nsI+1 > ih { 96 // Invalid domain 97 return "", fmt.Errorf("hostname is a not a Kubernetes name, missing namespace: %v", hostname) 98 } 99 ns := hostname[nsI+1 : ih] 100 if len(ns) == 0 { 101 return "", fmt.Errorf("namespace not found") 102 } 103 return ns, nil 104 } 105 106 func (r *Cache) DependentConfigs() []model.ConfigHash { 107 size := len(r.Services) + len(r.VirtualServices) + len(r.DelegateVirtualServices) + len(r.EnvoyFilterKeys) 108 for _, mergedDR := range r.DestinationRules { 109 size += len(mergedDR.GetFrom()) 110 } 111 configs := make([]model.ConfigHash, 0, size) 112 for _, svc := range r.Services { 113 configs = append(configs, model.ConfigKey{ 114 Kind: kind.ServiceEntry, 115 Name: string(svc.Hostname), 116 Namespace: svc.Attributes.Namespace, 117 }.HashCode()) 118 for _, alias := range svc.Attributes.Aliases { 119 configs = append(configs, model.ConfigKey{Kind: kind.ServiceEntry, Name: alias.Hostname.String(), Namespace: alias.Namespace}.HashCode()) 120 } 121 } 122 for _, vs := range r.VirtualServices { 123 for _, cfg := range model.VirtualServiceDependencies(vs) { 124 configs = append(configs, cfg.HashCode()) 125 } 126 } 127 // add delegate virtual services to dependent configs 128 // so that we can clear the rds cache when delegate virtual services are updated 129 configs = append(configs, r.DelegateVirtualServices...) 130 for _, mergedDR := range r.DestinationRules { 131 for _, dr := range mergedDR.GetFrom() { 132 configs = append(configs, model.ConfigKey{Kind: kind.DestinationRule, Name: dr.Name, Namespace: dr.Namespace}.HashCode()) 133 } 134 } 135 136 for _, efKey := range r.EnvoyFilterKeys { 137 items := strings.Split(efKey, "/") 138 configs = append(configs, model.ConfigKey{Kind: kind.EnvoyFilter, Name: items[1], Namespace: items[0]}.HashCode()) 139 } 140 return configs 141 } 142 143 func (r *Cache) Key() any { 144 // nolint: gosec 145 // Not security sensitive code 146 h := hash.New() 147 148 h.WriteString(r.RouteName) 149 h.Write(Separator) 150 h.WriteString(r.ProxyVersion) 151 h.Write(Separator) 152 h.WriteString(r.ClusterID) 153 h.Write(Separator) 154 h.WriteString(r.DNSDomain) 155 h.Write(Separator) 156 h.WriteString(strconv.FormatBool(r.DNSCapture)) 157 h.Write(Separator) 158 h.WriteString(strconv.FormatBool(r.DNSAutoAllocate)) 159 h.Write(Separator) 160 h.WriteString(strconv.FormatBool(r.AllowAny)) 161 h.Write(Separator) 162 163 for _, svc := range r.Services { 164 h.WriteString(string(svc.Hostname)) 165 h.Write(Slash) 166 h.WriteString(svc.Attributes.Namespace) 167 h.Write(Separator) 168 } 169 h.Write(Separator) 170 171 for _, vs := range r.VirtualServices { 172 for _, cfg := range model.VirtualServiceDependencies(vs) { 173 h.WriteString(cfg.Kind.String()) 174 h.Write(Slash) 175 h.WriteString(cfg.Name) 176 h.Write(Slash) 177 h.WriteString(cfg.Namespace) 178 h.Write(Separator) 179 } 180 } 181 h.Write(Separator) 182 183 for _, vs := range r.DelegateVirtualServices { 184 h.Write(hashToBytes(vs)) 185 h.Write(Separator) 186 } 187 h.Write(Separator) 188 189 for _, mergedDR := range r.DestinationRules { 190 for _, dr := range mergedDR.GetFrom() { 191 h.WriteString(dr.Name) 192 h.Write(Slash) 193 h.WriteString(dr.Namespace) 194 h.Write(Separator) 195 } 196 } 197 h.Write(Separator) 198 199 for _, efk := range r.EnvoyFilterKeys { 200 h.WriteString(efk) 201 h.Write(Separator) 202 } 203 h.Write(Separator) 204 205 return h.Sum64() 206 } 207 208 func hashToBytes(number model.ConfigHash) []byte { 209 big := new(big.Int) 210 big.SetUint64(uint64(number)) 211 return big.Bytes() 212 }