github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/selectorcache.go (about) 1 // Copyright 2019 Authors of Cilium 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 policy 16 17 import ( 18 "sort" 19 "strings" 20 "sync/atomic" 21 "unsafe" 22 23 "github.com/cilium/cilium/api/v1/models" 24 "github.com/cilium/cilium/pkg/identity" 25 "github.com/cilium/cilium/pkg/identity/cache" 26 k8sConst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io" 27 "github.com/cilium/cilium/pkg/labels" 28 "github.com/cilium/cilium/pkg/lock" 29 "github.com/cilium/cilium/pkg/logging/logfields" 30 "github.com/cilium/cilium/pkg/policy/api" 31 32 "github.com/sirupsen/logrus" 33 ) 34 35 // CachedSelector represents an identity selector owned by the selector cache 36 type CachedSelector interface { 37 // GetSelections returns the cached set of numeric identities 38 // selected by the CachedSelector. The retuned slice must NOT 39 // be modified, as it is shared among multiple users. 40 GetSelections() []identity.NumericIdentity 41 42 // Selects return 'true' if the CachedSelector selects the given 43 // numeric identity. 44 Selects(nid identity.NumericIdentity) bool 45 46 // IsWildcard returns true if the endpoint selector selects 47 // all endpoints. 48 IsWildcard() bool 49 50 // String returns the string representation of this selector. 51 // Used as a map key. 52 String() string 53 } 54 55 // CachedSelectorSlice is a slice of CachedSelectors that can be sorted. 56 type CachedSelectorSlice []CachedSelector 57 58 func (s CachedSelectorSlice) Len() int { return len(s) } 59 func (s CachedSelectorSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 60 61 func (s CachedSelectorSlice) Less(i, j int) bool { 62 return strings.Compare(s[i].String(), s[j].String()) < 0 63 } 64 65 // SelectsAllEndpoints returns whether the CachedSelectorSlice selects all 66 // endpoints, which is true if the wildcard endpoint selector is present in the 67 // slice. 68 func (s CachedSelectorSlice) SelectsAllEndpoints() bool { 69 for _, selector := range s { 70 if selector.IsWildcard() { 71 return true 72 } 73 } 74 return false 75 } 76 77 // Insert in a sorted order? Returns true if inserted, false if cs was already in 78 func (s *CachedSelectorSlice) Insert(cs CachedSelector) bool { 79 for _, selector := range *s { 80 if selector == cs { 81 return false 82 } 83 } 84 *s = append(*s, cs) 85 return true 86 } 87 88 // CachedSelectionUser inserts selectors into the cache and gets update 89 // callbacks whenever the set of selected numeric identities change for 90 // the CachedSelectors pushed by it. 91 type CachedSelectionUser interface { 92 // IdentitySelectionUpdated implementations MUST NOT call back 93 // to the name manager or the selector cache while executing this function! 94 // 95 // The caller is responsible for making sure the same identity is not 96 // present in both 'added' and 'deleted'. 97 IdentitySelectionUpdated(selector CachedSelector, selections, added, deleted []identity.NumericIdentity) 98 } 99 100 // identitySelector is the internal interface for all selectors in the 101 // selector cache. 102 // 103 // identitySelector represents the mapping of an EndpointSelector 104 // to a slice of identities. These mappings are updated via two 105 // different processes: 106 // 107 // 1. When policy rules are changed these are added and/or deleted 108 // depending on what selectors the rules contain. Cached selections of 109 // new identitySelectors are pre-populated from the set of currently 110 // known identities. 111 // 112 // 2. When reachacble identities appear or disappear, either via local 113 // allocation (CIDRs), or via the KV-store (remote endpoints). In this 114 // case all existing identitySelectors are walked through and their 115 // cached selections are updated as necessary. 116 // 117 // In both of the above cases the set of existing identitySelectors is 118 // write locked. 119 // 120 // To minimize the upkeep the identity selectors are shared across 121 // all IdentityPolicies, so that only one copy exists for each 122 // identitySelector. Users of the SelectorCache take care of creating 123 // identitySelectors as needed by identity policies. The set of 124 // identitySelectors is read locked during an IdentityPolicy update so 125 // that the the policy is always updated using a coherent set of 126 // cached selections. 127 // 128 // identitySelector is used as a map key, so it must not be implemented by a 129 // map, slice, or a func, or a runtime panic will be triggered. In all 130 // cases below identitySelector is being implemented by structs. 131 type identitySelector interface { 132 CachedSelector 133 addUser(CachedSelectionUser) (added bool) 134 135 // Called with NameManager and SelectorCache locks held 136 removeUser(CachedSelectionUser, identityNotifier) (last bool) 137 138 // This may be called while the NameManager lock is held 139 notifyUsers(added, deleted []identity.NumericIdentity) 140 141 numUsers() int 142 } 143 144 // scIdentity is the information we need about a an identity that rules can select 145 type scIdentity struct { 146 NID identity.NumericIdentity 147 lbls labels.LabelArray 148 namespace string // value of the namespace label, or "" 149 } 150 151 // scIdentityCache is a cache of Identities keyed by the numeric identity 152 type scIdentityCache map[identity.NumericIdentity]scIdentity 153 154 func newIdentity(nid identity.NumericIdentity, lbls labels.LabelArray) scIdentity { 155 return scIdentity{ 156 NID: nid, 157 lbls: lbls, 158 namespace: lbls.Get(labels.LabelSourceK8sKeyPrefix + k8sConst.PodNamespaceLabel), 159 } 160 } 161 162 func getIdentityCache(ids cache.IdentityCache) scIdentityCache { 163 idCache := make(map[identity.NumericIdentity]scIdentity, len(ids)) 164 for nid, lbls := range ids { 165 idCache[nid] = newIdentity(nid, lbls) 166 } 167 return idCache 168 } 169 170 // SelectorCache caches identities, identity selectors, and the 171 // subsets of identities each selector selects. 172 type SelectorCache struct { 173 mutex lock.RWMutex 174 175 // idCache contains all known identities as informed by the 176 // kv-store and the local identity facility via our 177 // UpdateIdentities() function. 178 idCache scIdentityCache 179 180 // map key is the string representation of the selector being cached. 181 selectors map[string]identitySelector 182 183 localIdentityNotifier identityNotifier 184 } 185 186 // GetModel returns the API model of the SelectorCache. 187 func (sc *SelectorCache) GetModel() models.SelectorCache { 188 sc.mutex.RLock() 189 defer sc.mutex.RUnlock() 190 191 selCacheMdl := make(models.SelectorCache, 0, len(sc.selectors)) 192 193 for selector, idSel := range sc.selectors { 194 selections := idSel.GetSelections() 195 ids := make([]int64, 0, len(selections)) 196 for i := range selections { 197 ids = append(ids, int64(selections[i])) 198 } 199 selMdl := &models.SelectorIdentityMapping{ 200 Selector: selector, 201 Identities: ids, 202 Users: int64(idSel.numUsers()), 203 } 204 selCacheMdl = append(selCacheMdl, selMdl) 205 } 206 207 return selCacheMdl 208 } 209 210 // NewSelectorCache creates a new SelectorCache with the given identities. 211 func NewSelectorCache(ids cache.IdentityCache) *SelectorCache { 212 return &SelectorCache{ 213 idCache: getIdentityCache(ids), 214 selectors: make(map[string]identitySelector), 215 } 216 } 217 218 // SetLocalIdentityNotifier injects the provided identityNotifier into the 219 // SelectorCache. Currently, this is used to inject the FQDN subsystem into 220 // the SelectorCache so the SelectorCache can notify the FQDN subsystem when 221 // it should be aware of a given FQDNSelector for which CIDR identities need 222 // to be provided upon DNS lookups which corespond to said FQDNSelector. 223 func (sc *SelectorCache) SetLocalIdentityNotifier(pop identityNotifier) { 224 sc.localIdentityNotifier = pop 225 } 226 227 var ( 228 // Empty slice of numeric identities used for all selectors that select nothing 229 emptySelection []identity.NumericIdentity 230 // wildcardSelectorKey is used to compare if a key is for a wildcard 231 wildcardSelectorKey = api.WildcardEndpointSelector.LabelSelector.String() 232 ) 233 234 type selectorManager struct { 235 key string 236 selections unsafe.Pointer // *[]identity.NumericIdentity 237 users map[CachedSelectionUser]struct{} 238 cachedSelections map[identity.NumericIdentity]struct{} 239 } 240 241 // Equal is used by checker.Equals, and only considers the identity of the selector, 242 // ignoring the internal state! 243 func (s *selectorManager) Equal(b *selectorManager) bool { 244 return s.key == b.key 245 } 246 247 // 248 // CachedSelector implementation (== Public API) 249 // 250 // No locking needed. 251 // 252 253 // GetSelections returns the set of numeric identities currently 254 // selected. The cached selections can be concurrently updated. In 255 // that case GetSelections() will return either the old or new version 256 // of the selections. If the old version is returned, the user is 257 // guaranteed to receive a notification including the update. 258 func (s *selectorManager) GetSelections() []identity.NumericIdentity { 259 return *(*[]identity.NumericIdentity)(atomic.LoadPointer(&s.selections)) 260 } 261 262 // Selects return 'true' if the CachedSelector selects the given 263 // numeric identity. 264 func (s *selectorManager) Selects(nid identity.NumericIdentity) bool { 265 if s.IsWildcard() { 266 return true 267 } 268 nids := s.GetSelections() 269 idx := sort.Search(len(nids), func(i int) bool { return nids[i] >= nid }) 270 return idx < len(nids) && nids[idx] == nid 271 } 272 273 // IsWildcard returns true if the endpoint selector selects all 274 // endpoints. 275 func (s *selectorManager) IsWildcard() bool { 276 return s.key == wildcardSelectorKey 277 } 278 279 // String returns the map key for this selector 280 func (s *selectorManager) String() string { 281 return s.key 282 } 283 284 // 285 // identitySelector implementation (== internal API) 286 // 287 288 // lock must be held 289 func (s *selectorManager) addUser(user CachedSelectionUser) (added bool) { 290 if _, exists := s.users[user]; exists { 291 return false 292 } 293 s.users[user] = struct{}{} 294 return true 295 } 296 297 // lock must be held 298 func (s *selectorManager) removeUser(user CachedSelectionUser, dnsProxy identityNotifier) (last bool) { 299 delete(s.users, user) 300 return len(s.users) == 0 301 } 302 303 // locks must be held for the dnsProxy and the SelectorCache 304 func (f *fqdnSelector) removeUser(user CachedSelectionUser, dnsProxy identityNotifier) (last bool) { 305 delete(f.users, user) 306 if len(f.users) == 0 { 307 dnsProxy.UnregisterForIdentityUpdatesLocked(f.selector) 308 return true 309 } 310 return false 311 } 312 313 // lock must be held 314 // 315 // The caller is responsible for making sure the same identity is not 316 // present in both 'added' and 'deleted'. 317 func (s *selectorManager) notifyUsers(added, deleted []identity.NumericIdentity) { 318 for user := range s.users { 319 user.IdentitySelectionUpdated(s, s.GetSelections(), added, deleted) 320 } 321 } 322 323 // lock must be held 324 func (s *selectorManager) numUsers() int { 325 return len(s.users) 326 } 327 328 // updateSelections updates the immutable slice representation of the 329 // cached selections after the cached selections have been changed. 330 // 331 // lock must be held 332 func (s *selectorManager) updateSelections() { 333 selections := make([]identity.NumericIdentity, len(s.cachedSelections)) 334 i := 0 335 for nid := range s.cachedSelections { 336 selections[i] = nid 337 i++ 338 } 339 // Sort the numeric identities so that the map iteration order 340 // does not matter. This makes testing easier, but may help 341 // identifying changes easier also otherwise. 342 sort.Slice(selections, func(i, j int) bool { 343 return selections[i] < selections[j] 344 }) 345 s.setSelections(&selections) 346 } 347 348 func (s *selectorManager) setSelections(selections *[]identity.NumericIdentity) { 349 if len(*selections) > 0 { 350 atomic.StorePointer(&s.selections, unsafe.Pointer(selections)) 351 } else { 352 atomic.StorePointer(&s.selections, unsafe.Pointer(&emptySelection)) 353 } 354 } 355 356 type fqdnSelector struct { 357 selectorManager 358 selector api.FQDNSelector 359 } 360 361 // identityNotifier provides a means for other subsystems to be made aware of a 362 // given FQDNSelector (currently pkg/fqdn) so that said subsystems can notify 363 // the SelectorCache about new IPs (via CIDR Identities) which correspond to 364 // said FQDNSelector. This is necessary since there is nothing intrinsic to a 365 // CIDR Identity that says that it corresponds to a given FQDNSelector; this 366 // relationship is contained only via DNS responses, which are handled 367 // externally. 368 type identityNotifier interface { 369 // Lock must be held during any calls to RegisterForIdentityUpdatesLocked or 370 // UnregisterForIdentityUpdatesLocked. 371 Lock() 372 373 // Unlock must be called after calls to RegisterForIdentityUpdatesLocked or 374 // UnregisterForIdentityUpdatesLocked are done. 375 Unlock() 376 377 // RegisterForIdentityUpdatesLocked exposes this FQDNSelector so that identities 378 // for IPs contained in a DNS response that matches said selector can be 379 // propagated back to the SelectorCache via `UpdateFQDNSelector`. When called, 380 // implementers (currently `pkg/fqdn/RuleGen`) should iterate over all DNS 381 // names that they are aware of, and see if they match the FQDNSelector. 382 // All IPs which correspond to the DNS names which match this Selector will 383 // be returned as CIDR identities, as other DNS Names which have already 384 // been resolved may match this FQDNSelector. 385 // Once this function is called, the SelectorCache will be updated any time 386 // new IPs are resolved for DNS names which match this FQDNSelector. 387 // This function is only called when the SelectorCache has been made aware 388 // of this FQDNSelector for the first time, since we only need to get the 389 // set of CIDR identities which match this FQDNSelector already from the 390 // identityNotifier on the first pass; any subsequent updates will eventually 391 // call `UpdateFQDNSelector`. 392 RegisterForIdentityUpdatesLocked(selector api.FQDNSelector) (identities []identity.NumericIdentity) 393 394 // UnregisterForIdentityUpdatesLocked removes this FQDNSelector from the set of 395 // FQDNSelectors which are being tracked by the identityNotifier. The result 396 // of this is that no more updates for IPs which correspond to said selector 397 // are propagated back to the SelectorCache via `UpdateFQDNSelector`. 398 // This occurs when there are no more users of a given FQDNSelector for the 399 // SelectorCache. 400 UnregisterForIdentityUpdatesLocked(selector api.FQDNSelector) 401 } 402 403 type labelIdentitySelector struct { 404 selectorManager 405 selector api.EndpointSelector 406 namespaces []string // allowed namespaces, or "" 407 } 408 409 // xxxMatches returns true if the CachedSelector matches given labels. 410 // This is slow, but only used for policy tracing, so it's OK. 411 func (l *labelIdentitySelector) xxxMatches(labels labels.LabelArray) bool { 412 return l.selector.Matches(labels) 413 } 414 415 func (l *labelIdentitySelector) matchesNamespace(ns string) bool { 416 if len(l.namespaces) > 0 { 417 if ns != "" { 418 for i := range l.namespaces { 419 if ns == l.namespaces[i] { 420 return true 421 } 422 } 423 } 424 // namespace required, but no match 425 return false 426 } 427 // no namespace required, match 428 return true 429 } 430 431 func (l *labelIdentitySelector) matches(identity scIdentity) bool { 432 return l.matchesNamespace(identity.namespace) && l.selector.Matches(identity.lbls) 433 } 434 435 // 436 // CachedSelector implementation (== Public API) 437 // 438 // No locking needed. 439 // 440 441 // UpdateFQDNSelector updates the mapping of fqdnKey (the FQDNSelector from a 442 // policy rule as a string) to to the provided list of identities. If the contents 443 // of the cachedSelections differ from those in the identities slice, all 444 // users are notified. 445 func (sc *SelectorCache) UpdateFQDNSelector(fqdnSelec api.FQDNSelector, identities []identity.NumericIdentity) { 446 sc.mutex.Lock() 447 sc.updateFQDNSelector(fqdnSelec, identities) 448 sc.mutex.Unlock() 449 } 450 451 func (sc *SelectorCache) updateFQDNSelector(fqdnSelec api.FQDNSelector, identities []identity.NumericIdentity) { 452 fqdnKey := fqdnSelec.String() 453 454 var fqdnSel *fqdnSelector 455 456 selector, exists := sc.selectors[fqdnKey] 457 if !exists || selector == nil { 458 fqdnSel = &fqdnSelector{ 459 selectorManager: selectorManager{ 460 key: fqdnKey, 461 users: make(map[CachedSelectionUser]struct{}), 462 cachedSelections: make(map[identity.NumericIdentity]struct{}), 463 }, 464 selector: fqdnSelec, 465 } 466 sc.selectors[fqdnKey] = fqdnSel 467 } else { 468 fqdnSel = selector.(*fqdnSelector) 469 } 470 471 // Convert identity slice to map for comparison with cachedSelections map. 472 idsAsMap := make(map[identity.NumericIdentity]struct{}, len(identities)) 473 for _, v := range identities { 474 idsAsMap[v] = struct{}{} 475 } 476 477 // Note that 'added' and 'deleted' are guaranteed to be 478 // disjoint, as one of them is left as nil, or an identity 479 // being in 'identities' is a precondition for an 480 // identity to be appended to 'added', while the inverse is 481 // true for 'deleted'. 482 var added, deleted []identity.NumericIdentity 483 484 /* TODO - the FQDN side should expose what was changed (IPs added, and removed) 485 * not all IPs corresponding to an FQDN - this will make this diff much 486 * cheaper, but will require more plumbing on the FQDN side. for now, this 487 * is good enough. 488 * 489 * Case 1: identities did correspond to this FQDN, but no longer do. Reset 490 * the map 491 */ 492 if len(identities) == 0 && len(fqdnSel.cachedSelections) != 0 { 493 // Need to update deleted to be all in cached selections 494 for k := range fqdnSel.cachedSelections { 495 deleted = append(deleted, k) 496 } 497 fqdnSel.cachedSelections = make(map[identity.NumericIdentity]struct{}) 498 } else if len(identities) != 0 && len(fqdnSel.cachedSelections) == 0 { 499 // Case 2: identities now correspond to this FQDN, but didn't before. 500 // We don't have to do any comparison of the maps to see what changed 501 // and what didn't. 502 added = identities 503 fqdnSel.cachedSelections = idsAsMap 504 } else { 505 // Case 3: Something changed resulting in some identities being added 506 // and / or removed. Figure out what these sets are (new identities 507 // added, or identities deleted). 508 for k := range fqdnSel.cachedSelections { 509 // If identity in cached selectors isn't in identities which were 510 // passed in, mark it as being deleted, and remove it from 511 // cachedSelectors. 512 if _, ok := idsAsMap[k]; !ok { 513 deleted = append(deleted, k) 514 delete(fqdnSel.cachedSelections, k) 515 } 516 } 517 518 // Now iterate over the provided identities to update the 519 // cachedSelections accordingly, and so we can see which identities 520 // were actually added (removing those which were added already). 521 for _, allowedIdentity := range identities { 522 if _, ok := fqdnSel.cachedSelections[allowedIdentity]; !ok { 523 // This identity was actually added and not already in the map. 524 added = append(added, allowedIdentity) 525 fqdnSel.cachedSelections[allowedIdentity] = struct{}{} 526 } 527 } 528 } 529 530 // Note: we don't need to go through the identity cache to see what 531 // identities match" this selector. This has to be updated via whatever is 532 // getting the CIDR identities which correspond to this FQDNSelector. This 533 // is the primary difference here between FQDNSelector and IdentitySelector. 534 fqdnSel.updateSelections() 535 fqdnSel.notifyUsers(added, deleted) // disjoint sets, see the comment above 536 } 537 538 // AddFQDNSelector adds the given api.FQDNSelector in to the selector cache. If 539 // an identical EndpointSelector has already been cached, the corresponding 540 // CachedSelector is returned, otherwise one is created and added to the cache. 541 func (sc *SelectorCache) AddFQDNSelector(user CachedSelectionUser, fqdnSelec api.FQDNSelector) (cachedSelector CachedSelector, added bool) { 542 key := fqdnSelec.String() 543 544 // Lock NameManager before the SelectorCache 545 sc.localIdentityNotifier.Lock() 546 defer sc.localIdentityNotifier.Unlock() 547 548 // If the selector already exists, use it. 549 sc.mutex.Lock() 550 fqdnSel, exists := sc.selectors[key] 551 if exists { 552 added := fqdnSel.addUser(user) 553 sc.mutex.Unlock() 554 return fqdnSel, added 555 } 556 sc.mutex.Unlock() 557 558 // Create the new selector. Pulling the identities it selects could 559 // cause allocation of new CIDR identities, so we do this while not 560 // holding the 'sc.mutex'. 561 newFQDNSel := &fqdnSelector{ 562 selectorManager: selectorManager{ 563 key: key, 564 users: make(map[CachedSelectionUser]struct{}), 565 cachedSelections: make(map[identity.NumericIdentity]struct{}), 566 }, 567 selector: fqdnSelec, 568 } 569 570 // Make the FQDN subsystem aware of this selector and fetch identities 571 // that the FQDN subsystem is aware of. 572 // 573 // If the same 'fqdnSelec' is registered twice here from different 574 // goroutines, we do *NOT* need to unregister the second one because 575 // 'fqdnSelec' is just a struct passed by value. The call below doesn't 576 // retain any references/pointers. 577 // 578 // If this is called twice, one of the results will arbitrarily contain 579 // a real slice of ids, while the other will receive nil. We must fold 580 // them together below. 581 ids := sc.localIdentityNotifier.RegisterForIdentityUpdatesLocked(newFQDNSel.selector) 582 583 // Do not go through the identity cache to see what identities "match" this 584 // selector. This has to be updated via whatever is getting the CIDR identities 585 // which correspond go this FQDNSelector. 586 // Alternatively , we could go through the CIDR identities in the cache 587 // provided they have some 'field' which shows which FQDNs they correspond 588 // to? This would require we keep some set in the Identity for the CIDR. 589 // Is this feasible? 590 591 // Note: No notifications are sent for the existing 592 // identities. Caller must use GetSelections() to get the 593 // current selections after adding a selector. This way the 594 // behavior is the same between the two cases here (selector 595 // is already cached, or is a new one). 596 597 sc.mutex.Lock() 598 defer sc.mutex.Unlock() 599 600 // Check whether the selectorCache was updated while 'newFQDNSel' was 601 // being registered without the 'sc.mutex'. If so, use it. Otherwise 602 // we can use the one we just created/configured above. 603 if sel, exists := sc.selectors[key]; exists { 604 newFQDNSel = sel.(*fqdnSelector) 605 } else { 606 sc.selectors[key] = newFQDNSel 607 } 608 609 // Add the ids from the slice above to the FQDN selector in the cache. 610 // This could plausibly happen twice, once with an empty 'ids' slice 611 // and once with the real 'ids' slice. Either way, they are added to 612 // the selector that is stored in 'sc.selectors[]' 613 for _, id := range ids { 614 newFQDNSel.cachedSelections[id] = struct{}{} 615 } 616 newFQDNSel.updateSelections() 617 618 return newFQDNSel, newFQDNSel.addUser(user) 619 } 620 621 // FindCachedIdentitySelector finds the given api.EndpointSelector in the 622 // selector cache, returning nil if one can not be found. 623 func (sc *SelectorCache) FindCachedIdentitySelector(selector api.EndpointSelector) CachedSelector { 624 key := selector.CachedString() 625 sc.mutex.Lock() 626 idSel := sc.selectors[key] 627 sc.mutex.Unlock() 628 return idSel 629 } 630 631 // AddIdentitySelector adds the given api.EndpointSelector in to the 632 // selector cache. If an identical EndpointSelector has already been 633 // cached, the corresponding CachedSelector is returned, otherwise one 634 // is created and added to the cache. 635 func (sc *SelectorCache) AddIdentitySelector(user CachedSelectionUser, selector api.EndpointSelector) (cachedSelector CachedSelector, added bool) { 636 // The key returned here may be different for equivalent 637 // labelselectors, if the selector's requirements are stored 638 // in different orders. When this happens we'll be tracking 639 // essentially two copies of the same selector. 640 key := selector.CachedString() 641 sc.mutex.Lock() 642 defer sc.mutex.Unlock() 643 idSel, exists := sc.selectors[key] 644 if exists { 645 return idSel, idSel.addUser(user) 646 } 647 648 // Selectors are never modified once a rule is placed in the policy repository, 649 // so no need to deep copy. 650 651 newIDSel := &labelIdentitySelector{ 652 selectorManager: selectorManager{ 653 key: key, 654 users: make(map[CachedSelectionUser]struct{}), 655 cachedSelections: make(map[identity.NumericIdentity]struct{}), 656 }, 657 selector: selector, 658 } 659 // check is selector has a namespace match or requirement 660 if namespaces, ok := selector.GetMatch(labels.LabelSourceK8sKeyPrefix + k8sConst.PodNamespaceLabel); ok { 661 newIDSel.namespaces = namespaces 662 } 663 664 // Add the initial user 665 newIDSel.users[user] = struct{}{} 666 667 // Find all matching identities from the identity cache. 668 for numericID, identity := range sc.idCache { 669 if newIDSel.matches(identity) { 670 newIDSel.cachedSelections[numericID] = struct{}{} 671 } 672 } 673 // Create the immutable slice representation of the selected 674 // numeric identities 675 newIDSel.updateSelections() 676 677 // Note: No notifications are sent for the existing 678 // identities. Caller must use GetSelections() to get the 679 // current selections after adding a selector. This way the 680 // behavior is the same between the two cases here (selector 681 // is already cached, or is a new one). 682 683 sc.selectors[key] = newIDSel 684 return newIDSel, true 685 } 686 687 // lock must be held 688 func (sc *SelectorCache) removeSelectorLocked(selector CachedSelector, user CachedSelectionUser) { 689 key := selector.String() 690 sel, exists := sc.selectors[key] 691 if exists { 692 if sel.removeUser(user, sc.localIdentityNotifier) { 693 delete(sc.selectors, key) 694 } 695 } 696 } 697 698 // RemoveSelector removes CachedSelector for the user. 699 func (sc *SelectorCache) RemoveSelector(selector CachedSelector, user CachedSelectionUser) { 700 sc.localIdentityNotifier.Lock() 701 sc.mutex.Lock() 702 sc.removeSelectorLocked(selector, user) 703 sc.mutex.Unlock() 704 sc.localIdentityNotifier.Unlock() 705 } 706 707 // RemoveSelectors removes CachedSelectorSlice for the user. 708 func (sc *SelectorCache) RemoveSelectors(selectors CachedSelectorSlice, user CachedSelectionUser) { 709 sc.localIdentityNotifier.Lock() 710 sc.mutex.Lock() 711 for _, selector := range selectors { 712 sc.removeSelectorLocked(selector, user) 713 } 714 sc.mutex.Unlock() 715 sc.localIdentityNotifier.Unlock() 716 } 717 718 // ChangeUser changes the CachedSelectionUser that gets updates on the 719 // updates on the cached selector. 720 func (sc *SelectorCache) ChangeUser(selector CachedSelector, from, to CachedSelectionUser) { 721 key := selector.String() 722 sc.mutex.Lock() 723 idSel, exists := sc.selectors[key] 724 if exists { 725 // Add before remove so that the count does not dip to zero in between, 726 // as this causes FQDN unregistration (if applicable). 727 idSel.addUser(to) 728 // ignoring the return value as we have just added a user above 729 idSel.removeUser(from, sc.localIdentityNotifier) 730 } 731 sc.mutex.Unlock() 732 } 733 734 // UpdateIdentities propagates identity updates to selectors 735 // 736 // The caller is responsible for making sure the same identity is not 737 // present in both 'added' and 'deleted'. 738 func (sc *SelectorCache) UpdateIdentities(added, deleted cache.IdentityCache) { 739 sc.mutex.Lock() 740 defer sc.mutex.Unlock() 741 742 // Update idCache so that newly added selectors get 743 // prepopulated with all matching numeric identities. 744 for numericID := range deleted { 745 if old, exists := sc.idCache[numericID]; exists { 746 log.WithFields(logrus.Fields{logfields.Identity: numericID, logfields.Labels: old.lbls}).Debug("UpdateIdentities: Deleting identity") 747 delete(sc.idCache, numericID) 748 } else { 749 log.WithFields(logrus.Fields{logfields.Identity: numericID}).Warning("UpdateIdentities: Skipping Delete of a non-existing identity") 750 delete(deleted, numericID) 751 } 752 } 753 for numericID, lbls := range added { 754 if old, exists := sc.idCache[numericID]; exists { 755 // Skip if no change. Not skipping if label 756 // order is different, but identity labels are 757 // sorted for the kv-store, so there should 758 // not be too many false negatives. 759 if lbls.Same(old.lbls) { 760 log.WithFields(logrus.Fields{logfields.Identity: numericID}).Debug("UpdateIdentities: Skipping add of an existing identical identity") 761 delete(added, numericID) 762 continue 763 } 764 log.WithFields(logrus.Fields{logfields.Identity: numericID, logfields.Labels: old.lbls, logfields.Labels + "(new)": lbls}).Warning("UpdateIdentities: Updating an existing identity") 765 } else { 766 log.WithFields(logrus.Fields{logfields.Identity: numericID, logfields.Labels: lbls}).Debug("UpdateIdentities: Adding a new identity") 767 } 768 sc.idCache[numericID] = newIdentity(numericID, lbls) 769 } 770 771 if len(deleted)+len(added) > 0 { 772 // Iterate through all locally used identity selectors and 773 // update the cached numeric identities as required. 774 for _, sel := range sc.selectors { 775 var adds, dels []identity.NumericIdentity 776 switch idSel := sel.(type) { 777 case *labelIdentitySelector: 778 for numericID := range deleted { 779 if _, exists := idSel.cachedSelections[numericID]; exists { 780 dels = append(dels, numericID) 781 delete(idSel.cachedSelections, numericID) 782 } 783 } 784 for numericID := range added { 785 if _, exists := idSel.cachedSelections[numericID]; !exists { 786 if idSel.matches(sc.idCache[numericID]) { 787 adds = append(adds, numericID) 788 idSel.cachedSelections[numericID] = struct{}{} 789 } 790 } 791 } 792 if len(dels)+len(adds) > 0 { 793 idSel.updateSelections() 794 idSel.notifyUsers(adds, dels) 795 } 796 case *fqdnSelector: 797 // This is a no-op right now. We don't encode in the identities 798 // which FQDNs they correspond to. 799 } 800 } 801 } 802 } 803 804 // RemoveIdentitiesFQDNSelectors removes all identities from being mapped to the 805 // set of FQDNSelectors. 806 func (sc *SelectorCache) RemoveIdentitiesFQDNSelectors(fqdnSels []api.FQDNSelector) { 807 sc.mutex.Lock() 808 noIdentities := []identity.NumericIdentity{} 809 810 for i := range fqdnSels { 811 sc.updateFQDNSelector(fqdnSels[i], noIdentities) 812 } 813 sc.mutex.Unlock() 814 }