github.phpd.cn/cilium/cilium@v1.6.12/pkg/identity/cache/local.go (about) 1 // Copyright 2018 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 cache 16 17 import ( 18 "fmt" 19 20 "github.com/cilium/cilium/pkg/allocator" 21 "github.com/cilium/cilium/pkg/identity" 22 "github.com/cilium/cilium/pkg/idpool" 23 "github.com/cilium/cilium/pkg/kvstore" 24 "github.com/cilium/cilium/pkg/labels" 25 "github.com/cilium/cilium/pkg/lock" 26 ) 27 28 type localIdentityCache struct { 29 mutex lock.RWMutex 30 identitiesByID map[identity.NumericIdentity]*identity.Identity 31 identitiesByLabels map[string]*identity.Identity 32 nextNumericIdentity identity.NumericIdentity 33 minID identity.NumericIdentity 34 maxID identity.NumericIdentity 35 events allocator.AllocatorEventChan 36 } 37 38 func newLocalIdentityCache(minID, maxID identity.NumericIdentity, events allocator.AllocatorEventChan) *localIdentityCache { 39 return &localIdentityCache{ 40 identitiesByID: map[identity.NumericIdentity]*identity.Identity{}, 41 identitiesByLabels: map[string]*identity.Identity{}, 42 nextNumericIdentity: minID, 43 minID: minID, 44 maxID: maxID, 45 events: events, 46 } 47 } 48 49 func (l *localIdentityCache) bumpNextNumericIdentity() { 50 if l.nextNumericIdentity == l.maxID { 51 l.nextNumericIdentity = l.minID 52 } else { 53 l.nextNumericIdentity++ 54 } 55 } 56 57 // getNextFreeNumericIdentity returns the next available numeric identity or an error 58 // The l.mutex must be held 59 func (l *localIdentityCache) getNextFreeNumericIdentity() (identity.NumericIdentity, error) { 60 firstID := l.nextNumericIdentity 61 for { 62 idCandidate := l.nextNumericIdentity | identity.LocalIdentityFlag 63 if _, ok := l.identitiesByID[idCandidate]; !ok { 64 l.bumpNextNumericIdentity() 65 return idCandidate, nil 66 } 67 68 l.bumpNextNumericIdentity() 69 if l.nextNumericIdentity == firstID { 70 return 0, fmt.Errorf("out of local identity space") 71 } 72 } 73 } 74 75 // lookupOrCreate searches for the existence of a local identity with the given 76 // labels. If it exists, the reference count is incremented and the identity is 77 // returned. If it does not exist, a new identity is created with a unique 78 // numeric identity. All identities returned by lookupOrCreate() must be 79 // released again via localIdentityCache.release(). 80 func (l *localIdentityCache) lookupOrCreate(lbls labels.Labels) (*identity.Identity, bool, error) { 81 l.mutex.Lock() 82 defer l.mutex.Unlock() 83 84 stringRepresentation := string(lbls.SortedList()) 85 if id, ok := l.identitiesByLabels[stringRepresentation]; ok { 86 id.ReferenceCount++ 87 return id, false, nil 88 } 89 90 numericIdentity, err := l.getNextFreeNumericIdentity() 91 if err != nil { 92 return nil, false, err 93 } 94 95 id := &identity.Identity{ 96 ID: numericIdentity, 97 Labels: lbls, 98 LabelArray: lbls.LabelArray(), 99 ReferenceCount: 1, 100 } 101 102 l.identitiesByLabels[stringRepresentation] = id 103 l.identitiesByID[numericIdentity] = id 104 105 if l.events != nil { 106 l.events <- allocator.AllocatorEvent{ 107 Typ: kvstore.EventTypeCreate, 108 ID: idpool.ID(id.ID), 109 Key: GlobalIdentity{id.LabelArray}, 110 } 111 } 112 113 return id, true, nil 114 } 115 116 // release releases a local identity from the cache. true is returned when the 117 // last use of the identity has been released and the identity has been 118 // forgotten. 119 func (l *localIdentityCache) release(id *identity.Identity) bool { 120 l.mutex.Lock() 121 defer l.mutex.Unlock() 122 123 stringRepresentation := string(id.Labels.SortedList()) 124 if id, ok := l.identitiesByLabels[stringRepresentation]; ok { 125 switch { 126 case id.ReferenceCount > 1: 127 id.ReferenceCount-- 128 return false 129 130 case id.ReferenceCount == 1: 131 // Release is only attempted once, when the reference count is 132 // hitting the last use 133 stringRepresentation := string(id.Labels.SortedList()) 134 delete(l.identitiesByLabels, stringRepresentation) 135 delete(l.identitiesByID, id.ID) 136 137 if l.events != nil { 138 l.events <- allocator.AllocatorEvent{ 139 Typ: kvstore.EventTypeDelete, 140 ID: idpool.ID(id.ID), 141 } 142 } 143 144 return true 145 } 146 } 147 148 return false 149 } 150 151 // lookup searches for a local identity matching the given labels and returns 152 // it. If found, the reference count is NOT incremented and thus release must 153 // NOT be called. 154 func (l *localIdentityCache) lookup(lbls labels.Labels) *identity.Identity { 155 l.mutex.RLock() 156 defer l.mutex.RUnlock() 157 158 stringRepresentation := string(lbls.SortedList()) 159 if id, ok := l.identitiesByLabels[stringRepresentation]; ok { 160 return id 161 } 162 163 return nil 164 } 165 166 // lookupByID searches for a local identity matching the given ID and returns 167 // it. If found, the reference count is NOT incremented and thus release must 168 // NOT be called. 169 func (l *localIdentityCache) lookupByID(id identity.NumericIdentity) *identity.Identity { 170 l.mutex.RLock() 171 defer l.mutex.RUnlock() 172 173 if id, ok := l.identitiesByID[id]; ok { 174 return id 175 } 176 177 return nil 178 } 179 180 // GetIdentities returns all local identities 181 func (l *localIdentityCache) GetIdentities() map[identity.NumericIdentity]*identity.Identity { 182 cache := map[identity.NumericIdentity]*identity.Identity{} 183 184 l.mutex.RLock() 185 defer l.mutex.RUnlock() 186 187 for key, id := range l.identitiesByID { 188 cache[key] = id 189 } 190 191 return cache 192 }