github.phpd.cn/cilium/cilium@v1.6.12/pkg/service/id_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 service 16 17 import ( 18 "fmt" 19 20 "github.com/cilium/cilium/pkg/loadbalancer" 21 "github.com/cilium/cilium/pkg/lock" 22 ) 23 24 // IDAllocator contains an internal state of the ID allocator. 25 type IDAllocator struct { 26 // Protects entitiesID, entities, nextID and maxID 27 lock.RWMutex 28 29 // entitiesID is a map of all entities indexed by service or backend ID 30 entitiesID map[uint32]*loadbalancer.L3n4AddrID 31 32 // entities is a map of all entities indexed by L3n4Addr.StringID() 33 entities map[string]uint32 34 35 // nextID is the next ID to attempt to allocate 36 nextID uint32 37 38 // maxID is the maximum ID available for allocation 39 maxID uint32 40 41 // initNextID is the initial nextID 42 initNextID uint32 43 44 // initMaxID is the initial maxID 45 initMaxID uint32 46 } 47 48 var ( 49 serviceIDAlloc = NewIDAllocator(FirstFreeServiceID, MaxSetOfServiceID) 50 backendIDAlloc = NewIDAllocator(FirstFreeBackendID, MaxSetOfBackendID) 51 ) 52 53 // NewIDAllocator creates a new ID allocator instance. 54 func NewIDAllocator(nextID uint32, maxID uint32) *IDAllocator { 55 return &IDAllocator{ 56 entitiesID: map[uint32]*loadbalancer.L3n4AddrID{}, 57 entities: map[string]uint32{}, 58 nextID: nextID, 59 maxID: maxID, 60 initNextID: nextID, 61 initMaxID: maxID, 62 } 63 } 64 65 func (alloc *IDAllocator) addID(svc loadbalancer.L3n4Addr, id uint32) *loadbalancer.L3n4AddrID { 66 svcID := newID(svc, id) 67 alloc.entitiesID[id] = svcID 68 alloc.entities[svc.StringID()] = id 69 70 return svcID 71 } 72 73 func (alloc *IDAllocator) acquireLocalID(svc loadbalancer.L3n4Addr, desiredID uint32) (*loadbalancer.L3n4AddrID, error) { 74 alloc.Lock() 75 defer alloc.Unlock() 76 77 if svcID, ok := alloc.entities[svc.StringID()]; ok { 78 if svc, ok := alloc.entitiesID[svcID]; ok { 79 return svc, nil 80 } 81 } 82 83 if desiredID != 0 { 84 if _, ok := alloc.entitiesID[desiredID]; !ok { 85 return alloc.addID(svc, desiredID), nil 86 } 87 } 88 89 startingID := alloc.nextID 90 rollover := false 91 for { 92 if alloc.nextID == startingID && rollover { 93 break 94 } else if alloc.nextID == alloc.maxID { 95 alloc.nextID = FirstFreeServiceID 96 rollover = true 97 } 98 99 if _, ok := alloc.entitiesID[alloc.nextID]; !ok { 100 svcID := alloc.addID(svc, alloc.nextID) 101 alloc.nextID++ 102 return svcID, nil 103 } 104 105 alloc.nextID++ 106 } 107 108 return nil, fmt.Errorf("no service ID available") 109 } 110 111 func (alloc *IDAllocator) getLocalID(id uint32) (*loadbalancer.L3n4AddrID, error) { 112 alloc.RLock() 113 defer alloc.RUnlock() 114 115 if svc, ok := alloc.entitiesID[id]; ok { 116 return svc, nil 117 } 118 119 return nil, nil 120 } 121 122 func (alloc *IDAllocator) deleteLocalID(id uint32) error { 123 alloc.Lock() 124 defer alloc.Unlock() 125 126 if svc, ok := alloc.entitiesID[id]; ok { 127 delete(alloc.entitiesID, id) 128 delete(alloc.entities, svc.StringID()) 129 } 130 131 return nil 132 } 133 134 func (alloc *IDAllocator) lookupLocalID(svc loadbalancer.L3n4Addr) (uint32, error) { 135 alloc.RLock() 136 defer alloc.RUnlock() 137 138 if svcID, ok := alloc.entities[svc.StringID()]; ok { 139 return svcID, nil 140 } 141 142 return 0, fmt.Errorf("ID not found") 143 } 144 145 func (alloc *IDAllocator) setLocalIDSpace(next, max uint32) error { 146 alloc.Lock() 147 alloc.nextID = next 148 alloc.maxID = max 149 alloc.Unlock() 150 151 return nil 152 } 153 154 func (alloc *IDAllocator) getLocalMaxID() (uint32, error) { 155 alloc.RLock() 156 defer alloc.RUnlock() 157 return alloc.nextID, nil 158 } 159 160 func (alloc *IDAllocator) resetLocalID() { 161 alloc.Lock() 162 alloc.entitiesID = map[uint32]*loadbalancer.L3n4AddrID{} 163 alloc.entities = map[string]uint32{} 164 alloc.nextID = alloc.initNextID 165 alloc.maxID = alloc.initMaxID 166 alloc.Unlock() 167 } 168 169 func newID(svc loadbalancer.L3n4Addr, id uint32) *loadbalancer.L3n4AddrID { 170 return &loadbalancer.L3n4AddrID{ 171 L3n4Addr: svc, 172 ID: loadbalancer.ID(id), 173 } 174 }