github.com/fafucoder/cilium@v1.6.11/pkg/service/id_kvstore.go (about) 1 // Copyright 2016-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 "context" 19 "encoding/json" 20 "fmt" 21 "path" 22 "strconv" 23 24 "github.com/cilium/cilium/common" 25 "github.com/cilium/cilium/pkg/kvstore" 26 "github.com/cilium/cilium/pkg/loadbalancer" 27 "github.com/cilium/cilium/pkg/logging/logfields" 28 ) 29 30 func updateL3n4AddrIDRef(id loadbalancer.ID, l3n4AddrID loadbalancer.L3n4AddrID) error { 31 key := path.Join(ServiceIDKeyPath, strconv.FormatUint(uint64(id), 10)) 32 value, err := json.Marshal(l3n4AddrID) 33 if err != nil { 34 return err 35 } 36 return kvstore.Client().Set(key, value) 37 } 38 39 func initializeFreeID(path string, firstID uint32) error { 40 41 client := kvstore.Client() 42 kvLocker, err := client.LockPath(context.Background(), path) 43 if err != nil { 44 return err 45 } 46 defer kvLocker.Unlock() 47 48 log.Debug("Trying to acquire free ID...") 49 k, err := client.Get(path) 50 if err != nil { 51 return err 52 } 53 if k != nil { 54 // FreeID already set 55 return nil 56 } 57 58 marshaledID, err := json.Marshal(firstID) 59 if err != nil { 60 return fmt.Errorf("cannot marshal initialize id: %s", err) 61 } 62 63 err = client.Set(path, marshaledID) 64 if err != nil { 65 return err 66 } 67 68 return nil 69 } 70 71 // getMaxID returns the maximum possible free UUID stored. 72 func getMaxID(key string, firstID uint32) (uint32, error) { 73 client := kvstore.Client() 74 k, err := client.Get(key) 75 if err != nil { 76 return 0, err 77 } 78 if k == nil { 79 // FreeID is empty? We should set it out! 80 if err := initializeFreeID(key, firstID); err != nil { 81 return 0, err 82 } 83 // Due other goroutine can take the ID, still need to get the key from the kvstore. 84 k, err = client.Get(key) 85 if err != nil { 86 return 0, err 87 } 88 if k == nil { 89 // Something is really wrong 90 errMsg := "unable to retrieve last free ID because the key is always empty" 91 log.Error(errMsg) 92 return 0, fmt.Errorf(errMsg) 93 } 94 } 95 var freeID uint32 96 if err := json.Unmarshal(k, &freeID); err != nil { 97 return 0, err 98 } 99 return freeID, nil 100 } 101 102 func setMaxID(key string, firstID, maxID uint32) error { 103 client := kvstore.Client() 104 value, err := client.Get(key) 105 if err != nil { 106 return err 107 } 108 if value == nil { 109 // FreeID is empty? We should set it out! 110 if err := initializeFreeID(key, firstID); err != nil { 111 return err 112 } 113 k, err := client.Get(key) 114 if err != nil { 115 return err 116 } 117 if k == nil { 118 // Something is really wrong 119 errMsg := "unable to set ID because the key is always empty" 120 log.Error(errMsg) 121 return fmt.Errorf("%s", errMsg) 122 } 123 } 124 marshaledID, err := json.Marshal(maxID) 125 if err != nil { 126 return nil 127 } 128 return client.Set(key, marshaledID) 129 } 130 131 // gasNewL3n4AddrID gets and sets a new L3n4Addr ID. If baseID is different than zero, 132 // KVStore tries to assign that ID first. 133 func gasNewL3n4AddrID(l3n4AddrID *loadbalancer.L3n4AddrID, baseID uint32) error { 134 client := kvstore.Client() 135 136 if baseID == 0 { 137 var err error 138 baseID, err = getGlobalMaxServiceID() 139 if err != nil { 140 return err 141 } 142 } 143 144 setIDtoL3n4Addr := func(id uint32) error { 145 l3n4AddrID.ID = loadbalancer.ID(id) 146 marshaledL3n4AddrID, err := json.Marshal(l3n4AddrID) 147 if err != nil { 148 return err 149 } 150 keyPath := path.Join(ServiceIDKeyPath, strconv.FormatUint(uint64(l3n4AddrID.ID), 10)) 151 if err := client.Set(keyPath, marshaledL3n4AddrID); err != nil { 152 return err 153 } 154 155 return setMaxID(LastFreeServiceIDKeyPath, FirstFreeServiceID, id+1) 156 } 157 158 acquireFreeID := func(firstID uint32, incID *uint32) (bool, error) { 159 keyPath := path.Join(ServiceIDKeyPath, strconv.FormatUint(uint64(*incID), 10)) 160 161 locker, err := client.LockPath(context.Background(), keyPath) 162 if err != nil { 163 return false, err 164 } 165 defer locker.Unlock() 166 167 value, err := client.Get(keyPath) 168 if err != nil { 169 return false, err 170 } 171 if value == nil { 172 return false, setIDtoL3n4Addr(*incID) 173 } 174 var kvstoreL3n4AddrID loadbalancer.L3n4AddrID 175 if err := json.Unmarshal(value, &kvstoreL3n4AddrID); err != nil { 176 return false, err 177 } 178 if kvstoreL3n4AddrID.ID == 0 { 179 log.WithField(logfields.Identity, *incID).Info("Recycling Service ID") 180 return false, setIDtoL3n4Addr(*incID) 181 } 182 183 *incID++ 184 if *incID > MaxSetOfServiceID { 185 *incID = FirstFreeServiceID 186 } 187 if firstID == *incID { 188 return false, fmt.Errorf("reached maximum set of serviceIDs available") 189 } 190 // Only retry if we have incremented the service ID 191 return true, nil 192 } 193 194 beginning := baseID 195 for { 196 retry, err := acquireFreeID(beginning, &baseID) 197 if err != nil { 198 return err 199 } else if !retry { 200 return nil 201 } 202 } 203 } 204 205 // acquireGlobalID stores the given service in the kvstore and returns the L3n4AddrID 206 // created for the given l3n4Addr. If baseID is different than 0, it tries to acquire that 207 // ID to the l3n4Addr. 208 func acquireGlobalID(l3n4Addr loadbalancer.L3n4Addr, baseID uint32) (*loadbalancer.L3n4AddrID, error) { 209 // Retrieve unique SHA256Sum for service 210 sha256Sum := l3n4Addr.SHA256Sum() 211 svcPath := path.Join(common.ServicesKeyPath, sha256Sum) 212 213 // Lock that sha256Sum 214 lockKey, err := kvstore.LockPath(context.Background(), kvstore.Client(), svcPath) 215 if err != nil { 216 return nil, err 217 } 218 defer lockKey.Unlock() 219 220 // After lock complete, get svc's path 221 rmsg, err := kvstore.Client().Get(svcPath) 222 if err != nil { 223 return nil, err 224 } 225 226 sl4KV := loadbalancer.L3n4AddrID{} 227 if rmsg != nil { 228 if err := json.Unmarshal(rmsg, &sl4KV); err != nil { 229 return nil, err 230 } 231 } 232 if sl4KV.ID == 0 { 233 sl4KV.L3n4Addr = l3n4Addr 234 if err := gasNewL3n4AddrID(&sl4KV, baseID); err != nil { 235 return nil, err 236 } 237 marshaledSl4Kv, err := json.Marshal(sl4KV) 238 if err != nil { 239 return nil, err 240 } 241 err = kvstore.Client().Set(svcPath, marshaledSl4Kv) 242 if err != nil { 243 return nil, err 244 } 245 } 246 247 return &sl4KV, err 248 } 249 250 func getL3n4AddrID(keyPath string) (*loadbalancer.L3n4AddrID, error) { 251 rmsg, err := kvstore.Client().Get(keyPath) 252 if err != nil { 253 return nil, err 254 } 255 if rmsg == nil { 256 log.WithField("key", keyPath).Debug("no value mapped to key in KVStore") 257 return nil, nil 258 } 259 260 var l3n4AddrID loadbalancer.L3n4AddrID 261 if err := json.Unmarshal(rmsg, &l3n4AddrID); err != nil || l3n4AddrID.ID == 0 { 262 return nil, err 263 } 264 return &l3n4AddrID, nil 265 } 266 267 // getGlobalID returns the L3n4AddrID that belongs to the given id. 268 func getGlobalID(id uint32) (*loadbalancer.L3n4AddrID, error) { 269 strID := strconv.FormatUint(uint64(id), 10) 270 log.WithField(logfields.L3n4AddrID, strID).Debug("getting L3n4AddrID for ID") 271 272 return getL3n4AddrID(path.Join(ServiceIDKeyPath, strID)) 273 } 274 275 // deleteGlobalID deletes the L3n4AddrID belonging to the given id from the kvstore. 276 func deleteGlobalID(id uint32) error { 277 l3n4AddrID, err := getGlobalID(id) 278 if err != nil { 279 return err 280 } 281 if l3n4AddrID == nil { 282 return nil 283 } 284 285 return deleteL3n4AddrIDBySHA256(l3n4AddrID.SHA256Sum()) 286 } 287 288 // deleteL3n4AddrIDBySHA256 deletes the L3n4AddrID from the kvstore corresponding to the service's 289 // sha256Sum. 290 func deleteL3n4AddrIDBySHA256(sha256Sum string) error { 291 log.WithField(logfields.SHA, sha256Sum).Debug("deleting L3n4AddrID with SHA256") 292 if sha256Sum == "" { 293 return nil 294 } 295 svcPath := path.Join(common.ServicesKeyPath, sha256Sum) 296 // Lock that sha256Sum 297 lockKey, err := kvstore.LockPath(context.Background(), kvstore.Client(), svcPath) 298 if err != nil { 299 return err 300 } 301 defer lockKey.Unlock() 302 303 // After lock complete, get label's path 304 rmsg, err := kvstore.Client().Get(svcPath) 305 if err != nil { 306 return err 307 } 308 if rmsg == nil { 309 return nil 310 } 311 312 var l3n4AddrID loadbalancer.L3n4AddrID 313 if err := json.Unmarshal(rmsg, &l3n4AddrID); err != nil { 314 return err 315 } 316 oldL3n4ID := l3n4AddrID.ID 317 l3n4AddrID.ID = 0 318 319 // update the value in the kvstore 320 if err := updateL3n4AddrIDRef(oldL3n4ID, l3n4AddrID); err != nil { 321 return err 322 } 323 marshaledL3n4AddrID, err := json.Marshal(l3n4AddrID) 324 if err != nil { 325 return err 326 } 327 return kvstore.Client().Set(svcPath, marshaledL3n4AddrID) 328 } 329 330 func getGlobalMaxServiceID() (uint32, error) { 331 return getMaxID(LastFreeServiceIDKeyPath, FirstFreeServiceID) 332 } 333 334 func setGlobalIDSpace(next, max uint32) error { 335 return setMaxID(LastFreeServiceIDKeyPath, next, max) 336 }