github.com/form3tech-oss/cilium@v1.6.3/daemon/loadbalancer.go (about) 1 // Copyright 2016-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 main 16 17 import ( 18 "fmt" 19 "time" 20 21 "github.com/cilium/cilium/api/v1/models" 22 . "github.com/cilium/cilium/api/v1/server/restapi/service" 23 "github.com/cilium/cilium/pkg/api" 24 "github.com/cilium/cilium/pkg/loadbalancer" 25 "github.com/cilium/cilium/pkg/logging/logfields" 26 "github.com/cilium/cilium/pkg/maps/lbmap" 27 "github.com/cilium/cilium/pkg/option" 28 "github.com/cilium/cilium/pkg/service" 29 30 "github.com/go-openapi/runtime/middleware" 31 "github.com/sirupsen/logrus" 32 ) 33 34 // addSVC2BPFMap adds the given bpf service to the bpf maps. If addRevNAT is set, adds the 35 // RevNAT value (feCilium.L3n4Addr) to the lb's RevNAT map for the given feCilium.ID. 36 func (d *Daemon) addSVC2BPFMap(feCilium loadbalancer.L3n4AddrID, feBPF lbmap.ServiceKey, 37 besBPF []lbmap.ServiceValue, 38 svcKeyV2 lbmap.ServiceKeyV2, svcValuesV2 []lbmap.ServiceValueV2, backendsV2 []lbmap.Backend, 39 addRevNAT bool) error { 40 log.WithField(logfields.ServiceName, feCilium.String()).Debug("adding service to BPF maps") 41 42 revNATID := int(feCilium.ID) 43 44 if err := lbmap.UpdateService(feBPF, besBPF, addRevNAT, revNATID, 45 service.AcquireBackendID, service.DeleteBackendID); err != nil { 46 if addRevNAT { 47 delete(d.loadBalancer.RevNATMap, loadbalancer.ServiceID(feCilium.ID)) 48 } 49 return err 50 } 51 52 if addRevNAT { 53 log.WithField(logfields.ServiceName, feCilium.String()).Debug("adding service to RevNATMap") 54 d.loadBalancer.RevNATMap[loadbalancer.ServiceID(feCilium.ID)] = *feCilium.L3n4Addr.DeepCopy() 55 } 56 return nil 57 } 58 59 // SVCAdd is the public method to add services. We assume the ID provided is not in 60 // sync with the KVStore. If that's the, case the service won't be used and an error is 61 // returned to the caller. 62 // 63 // Returns true if service was created. 64 func (d *Daemon) SVCAdd(feL3n4Addr loadbalancer.L3n4AddrID, be []loadbalancer.LBBackEnd, addRevNAT bool) (bool, error) { 65 log.WithField(logfields.ServiceID, feL3n4Addr.String()).Debug("adding service") 66 if feL3n4Addr.ID == 0 { 67 return false, fmt.Errorf("invalid service ID 0") 68 } 69 // Check if the service is already registered with this ID. 70 feAddr, err := service.GetID(uint32(feL3n4Addr.ID)) 71 if err != nil { 72 return false, fmt.Errorf("unable to get service %d: %s", feL3n4Addr.ID, err) 73 } 74 if feAddr == nil { 75 feAddr, err = service.AcquireID(feL3n4Addr.L3n4Addr, uint32(feL3n4Addr.ID)) 76 if err != nil { 77 return false, fmt.Errorf("unable to store service %s in kvstore: %s", feL3n4Addr.String(), err) 78 } 79 // This won't be atomic so we need to check if the baseID, feL3n4Addr.ID was given to the service 80 if feAddr.ID != feL3n4Addr.ID { 81 return false, fmt.Errorf("the service provided %s is already registered with ID %d, please use that ID instead of %d", feL3n4Addr.L3n4Addr.String(), feAddr.ID, feL3n4Addr.ID) 82 } 83 } 84 85 feAddr256Sum := feAddr.L3n4Addr.SHA256Sum() 86 feL3n4Addr256Sum := feL3n4Addr.L3n4Addr.SHA256Sum() 87 88 if feAddr256Sum != feL3n4Addr256Sum { 89 return false, fmt.Errorf("service ID %d is already registered to L3n4Addr %s, please choose a different ID", feL3n4Addr.ID, feAddr.String()) 90 } 91 92 return d.svcAdd(feL3n4Addr, be, addRevNAT, false) 93 } 94 95 // svcAdd adds a service from the given feL3n4Addr (frontend) and LBBackEnd (backends). 96 // If addRevNAT is set, the RevNAT entry is also created for this particular service. 97 // If any of the backend addresses set in bes have a different L3 address type than the 98 // one set in fe, it returns an error without modifying the bpf LB map. If any backend 99 // entry fails while updating the LB map, the frontend won't be inserted in the LB map 100 // therefore there won't be any traffic going to the given backends. 101 // All of the backends added will be DeepCopied to the internal load balancer map. 102 func (d *Daemon) svcAdd( 103 feL3n4Addr loadbalancer.L3n4AddrID, bes []loadbalancer.LBBackEnd, 104 addRevNAT, nodePort bool) (bool, error) { 105 106 scopedLog := log.WithFields(logrus.Fields{ 107 logfields.ServiceID: feL3n4Addr.String(), 108 logfields.Object: logfields.Repr(bes), 109 }) 110 scopedLog.Debug("adding service") 111 112 // Move the slice to the loadbalancer map which has a mutex. If we don't 113 // copy the slice we might risk changing memory that should be locked. 114 beCpy := []loadbalancer.LBBackEnd{} 115 for _, v := range bes { 116 beCpy = append(beCpy, v) 117 } 118 119 svc := loadbalancer.LBSVC{ 120 FE: feL3n4Addr, 121 BES: beCpy, 122 Sha256: feL3n4Addr.L3n4Addr.SHA256Sum(), 123 NodePort: nodePort, 124 } 125 126 fe, besValues, err := lbmap.LBSVC2ServiceKeynValue(svc) 127 if err != nil { 128 return false, err 129 } 130 131 svcKeyV2, svcValuesV2, backendsV2, err := lbmap.LBSVC2ServiceKeynValuenBackendV2(&svc) 132 if err != nil { 133 return false, err 134 } 135 136 d.loadBalancer.BPFMapMU.Lock() 137 defer d.loadBalancer.BPFMapMU.Unlock() 138 139 err = d.addSVC2BPFMap(feL3n4Addr, fe, besValues, svcKeyV2, svcValuesV2, backendsV2, addRevNAT) 140 if err != nil { 141 return false, err 142 } 143 144 // Fill the just acquired backend IDs to ensure the consistent ordering 145 // of the backends when listing services. This step will go away once 146 // we start acquiring backend IDs in this module. 147 for i, be := range svc.BES { 148 id, err := service.LookupBackendID(be.L3n4Addr) 149 if err != nil { 150 scopedLog.WithField(logfields.BackendName, be.L3n4Addr).WithError(err). 151 Warning("Unable to lookup backend ID") 152 continue 153 } 154 svc.BES[i].ID = id 155 } 156 157 return d.loadBalancer.AddService(svc), nil 158 } 159 160 type putServiceID struct { 161 d *Daemon 162 } 163 164 func NewPutServiceIDHandler(d *Daemon) PutServiceIDHandler { 165 return &putServiceID{d: d} 166 } 167 168 func (h *putServiceID) Handle(params PutServiceIDParams) middleware.Responder { 169 log.WithField(logfields.Params, logfields.Repr(params)).Debug("PUT /service/{id} request") 170 171 f, err := loadbalancer.NewL3n4AddrFromModel(params.Config.FrontendAddress) 172 if err != nil { 173 return api.Error(PutServiceIDInvalidFrontendCode, err) 174 } 175 176 frontend := loadbalancer.L3n4AddrID{ 177 L3n4Addr: *f, 178 ID: loadbalancer.ID(params.Config.ID), 179 } 180 181 backends := []loadbalancer.LBBackEnd{} 182 for _, v := range params.Config.BackendAddresses { 183 b, err := loadbalancer.NewLBBackEndFromBackendModel(v) 184 if err != nil { 185 return api.Error(PutServiceIDInvalidBackendCode, err) 186 } 187 backends = append(backends, *b) 188 } 189 190 revnat := false 191 if params.Config.Flags != nil { 192 revnat = params.Config.Flags.DirectServerReturn 193 } 194 195 // FIXME 196 // Add flag to indicate whether service should be registered in 197 // global key value store 198 199 if created, err := h.d.SVCAdd(frontend, backends, revnat); err != nil { 200 return api.Error(PutServiceIDFailureCode, err) 201 } else if created { 202 return NewPutServiceIDCreated() 203 } else { 204 return NewPutServiceIDOK() 205 } 206 } 207 208 type deleteServiceID struct { 209 d *Daemon 210 } 211 212 func NewDeleteServiceIDHandler(d *Daemon) DeleteServiceIDHandler { 213 return &deleteServiceID{d: d} 214 } 215 216 func (h *deleteServiceID) Handle(params DeleteServiceIDParams) middleware.Responder { 217 log.WithField(logfields.Params, logfields.Repr(params)).Debug("DELETE /service/{id} request") 218 219 d := h.d 220 d.loadBalancer.BPFMapMU.Lock() 221 defer d.loadBalancer.BPFMapMU.Unlock() 222 223 svc, ok := d.loadBalancer.SVCMapID[loadbalancer.ServiceID(params.ID)] 224 225 if !ok { 226 return NewDeleteServiceIDNotFound() 227 } 228 229 // FIXME: How to handle error? 230 err := service.DeleteID(uint32(params.ID)) 231 232 if err != nil { 233 log.WithError(err).Warn("error, DeleteL3n4AddrIDByUUID failed") 234 } 235 236 if err := h.d.svcDelete(svc); err != nil { 237 log.WithError(err).WithField(logfields.Object, logfields.Repr(svc)).Warn("DELETE /service/{id}: error deleting service") 238 return api.Error(DeleteServiceIDFailureCode, err) 239 } 240 241 return NewDeleteServiceIDOK() 242 } 243 244 func (d *Daemon) svcDeleteByFrontendLocked(frontend *loadbalancer.L3n4AddrID) error { 245 svc, ok := d.loadBalancer.SVCMap[frontend.SHA256Sum()] 246 if !ok { 247 return fmt.Errorf("Service frontend not found %+v", frontend) 248 } 249 return d.svcDelete(&svc) 250 } 251 252 // Deletes a service by the frontend address 253 func (d *Daemon) svcDeleteByFrontend(frontend *loadbalancer.L3n4AddrID) error { 254 d.loadBalancer.BPFMapMU.Lock() 255 defer d.loadBalancer.BPFMapMU.Unlock() 256 257 return d.svcDeleteByFrontendLocked(frontend) 258 } 259 260 func (d *Daemon) svcDelete(svc *loadbalancer.LBSVC) error { 261 if err := d.svcDeleteBPF(svc.FE); err != nil { 262 return err 263 } 264 265 d.loadBalancer.DeleteService(svc) 266 267 return nil 268 } 269 270 func (d *Daemon) svcDeleteBPF(svc loadbalancer.L3n4AddrID) error { 271 if err := lbmap.DeleteServiceV2(svc, service.DeleteBackendID); err != nil { 272 return fmt.Errorf("Deleting service from BPF maps failed: %s", err) 273 } 274 275 lbmap.DeleteServiceCache(svc) 276 277 return nil 278 } 279 280 type getServiceID struct { 281 daemon *Daemon 282 } 283 284 func NewGetServiceIDHandler(d *Daemon) GetServiceIDHandler { 285 return &getServiceID{daemon: d} 286 } 287 288 func (h *getServiceID) Handle(params GetServiceIDParams) middleware.Responder { 289 log.WithField(logfields.Params, logfields.Repr(params)).Debug("GET /service/{id} request") 290 291 d := h.daemon 292 293 d.loadBalancer.BPFMapMU.RLock() 294 defer d.loadBalancer.BPFMapMU.RUnlock() 295 296 if svc, ok := d.loadBalancer.SVCMapID[loadbalancer.ServiceID(params.ID)]; ok { 297 return NewGetServiceIDOK().WithPayload(svc.GetModel()) 298 } 299 return NewGetServiceIDNotFound() 300 } 301 302 // SVCGetBySHA256Sum returns a DeepCopied frontend with its backends. 303 func (d *Daemon) svcGetBySHA256Sum(feL3n4SHA256Sum string) *loadbalancer.LBSVC { 304 d.loadBalancer.BPFMapMU.RLock() 305 defer d.loadBalancer.BPFMapMU.RUnlock() 306 307 v, ok := d.loadBalancer.SVCMap[feL3n4SHA256Sum] 308 if !ok { 309 return nil 310 } 311 // We will move the slice from the loadbalancer map which has a mutex. If 312 // we don't copy the slice we might risk changing memory that should be 313 // locked. 314 beCpy := []loadbalancer.LBBackEnd{} 315 for _, v := range v.BES { 316 beCpy = append(beCpy, v) 317 } 318 return &loadbalancer.LBSVC{ 319 FE: *v.FE.DeepCopy(), 320 BES: beCpy, 321 } 322 } 323 324 type getService struct { 325 d *Daemon 326 } 327 328 func NewGetServiceHandler(d *Daemon) GetServiceHandler { 329 return &getService{d: d} 330 } 331 332 func (h *getService) Handle(params GetServiceParams) middleware.Responder { 333 log.WithField(logfields.Params, logfields.Repr(params)).Debug("GET /service request") 334 list := h.d.GetServiceList() 335 return NewGetServiceOK().WithPayload(list) 336 } 337 338 // RevNATAdd deep copies the given revNAT address to the cilium lbmap with the given id. 339 func (d *Daemon) RevNATAdd(id loadbalancer.ServiceID, revNAT loadbalancer.L3n4Addr) error { 340 revNATK, revNATV := lbmap.L3n4Addr2RevNatKeynValue(id, revNAT) 341 342 d.loadBalancer.BPFMapMU.Lock() 343 defer d.loadBalancer.BPFMapMU.Unlock() 344 345 err := lbmap.UpdateRevNat(revNATK, revNATV) 346 if err != nil { 347 return err 348 } 349 350 d.loadBalancer.RevNATMap[id] = *revNAT.DeepCopy() 351 return nil 352 } 353 354 // RevNATDelete deletes the revNatKey from the local bpf map. 355 func (d *Daemon) RevNATDelete(id loadbalancer.ServiceID) error { 356 d.loadBalancer.BPFMapMU.Lock() 357 defer d.loadBalancer.BPFMapMU.Unlock() 358 359 revNAT, ok := d.loadBalancer.RevNATMap[id] 360 if !ok { 361 return nil 362 } 363 364 err := lbmap.DeleteRevNATBPF(id, revNAT.IsIPv6()) 365 366 // TODO should we delete even if err is != nil? 367 if err == nil { 368 delete(d.loadBalancer.RevNATMap, id) 369 } 370 return err 371 } 372 373 // RevNATDeleteAll deletes all RevNAT4, if IPv4 is enabled on daemon, and all RevNAT6 374 // stored on the daemon and on the bpf maps. 375 // 376 // Must be called with d.loadBalancer.BPFMapMU locked. 377 func (d *Daemon) RevNATDeleteAll() error { 378 if option.Config.EnableIPv4 { 379 if err := lbmap.RevNat4Map.DeleteAll(); err != nil { 380 return err 381 } 382 } 383 384 if option.Config.EnableIPv6 { 385 if err := lbmap.RevNat6Map.DeleteAll(); err != nil { 386 return err 387 } 388 } 389 390 // TODO should we delete even if err is != nil? 391 d.loadBalancer.RevNATMap = map[loadbalancer.ServiceID]loadbalancer.L3n4Addr{} 392 return nil 393 } 394 395 // RevNATGet returns a DeepCopy of the revNAT found with the given ID or nil if not found. 396 func (d *Daemon) RevNATGet(id loadbalancer.ServiceID) (*loadbalancer.L3n4Addr, error) { 397 d.loadBalancer.BPFMapMU.RLock() 398 defer d.loadBalancer.BPFMapMU.RUnlock() 399 400 revNAT, ok := d.loadBalancer.RevNATMap[id] 401 if !ok { 402 return nil, nil 403 } 404 return revNAT.DeepCopy(), nil 405 } 406 407 // RevNATDump dumps a DeepCopy of the cilium's loadbalancer. 408 func (d *Daemon) RevNATDump() ([]loadbalancer.L3n4AddrID, error) { 409 dump := []loadbalancer.L3n4AddrID{} 410 411 d.loadBalancer.BPFMapMU.RLock() 412 defer d.loadBalancer.BPFMapMU.RUnlock() 413 414 for k, v := range d.loadBalancer.RevNATMap { 415 dump = append(dump, loadbalancer.L3n4AddrID{ 416 ID: loadbalancer.ID(k), 417 L3n4Addr: *v.DeepCopy(), 418 }) 419 } 420 421 return dump, nil 422 } 423 424 func openServiceMaps() error { 425 if err := lbmap.RemoveDeprecatedMaps(); err != nil { 426 return err 427 } 428 429 if option.Config.EnableIPv6 { 430 if _, err := lbmap.Service6MapV2.OpenOrCreate(); err != nil { 431 return err 432 } 433 if _, err := lbmap.Backend6Map.OpenOrCreate(); err != nil { 434 return err 435 } 436 if _, err := lbmap.RevNat6Map.OpenOrCreate(); err != nil { 437 return err 438 } 439 if _, err := lbmap.RRSeq6MapV2.OpenOrCreate(); err != nil { 440 return err 441 } 442 } 443 444 if option.Config.EnableIPv4 { 445 if _, err := lbmap.Service4MapV2.OpenOrCreate(); err != nil { 446 return err 447 } 448 if _, err := lbmap.Backend4Map.OpenOrCreate(); err != nil { 449 return err 450 } 451 if _, err := lbmap.RevNat4Map.OpenOrCreate(); err != nil { 452 return err 453 } 454 if _, err := lbmap.RRSeq4MapV2.OpenOrCreate(); err != nil { 455 return err 456 } 457 } 458 459 return nil 460 } 461 462 // SyncLBMap syncs the bpf lbmap with the daemon's lb map. All bpf entries will overwrite 463 // the daemon's LB map. If the bpf lbmap entry has a different service ID than the 464 // KVStore's ID, that entry will be updated on the bpf map accordingly with the new ID 465 // retrieved from the KVStore. 466 func (d *Daemon) SyncLBMap() error { 467 // Don't bother syncing if we are in dry mode. 468 if option.Config.DryMode { 469 return nil 470 } 471 472 log.Info("Restoring services from BPF maps...") 473 474 d.loadBalancer.BPFMapMU.Lock() 475 defer d.loadBalancer.BPFMapMU.Unlock() 476 477 newSVCMapID := loadbalancer.SVCMapID{} 478 newRevNATMap := loadbalancer.RevNATMap{} 479 failedSyncSVC := []loadbalancer.LBSVC{} 480 failedSyncRevNAT := map[loadbalancer.ServiceID]loadbalancer.L3n4Addr{} 481 482 addSVC2BPFMap := func(oldID loadbalancer.ServiceID, svc loadbalancer.LBSVC) error { 483 scopedLog := log.WithFields(logrus.Fields{ 484 logfields.ServiceID: oldID, 485 logfields.SHA: svc.FE.SHA256Sum(), 486 }) 487 scopedLog.Debug("adding service ID with SHA") 488 489 // check if the ID for revNat is present in the bpf map, update the 490 // reverse nat key, delete the old one. 491 revNAT, ok := newRevNATMap[oldID] 492 if ok { 493 scopedLog.Debug("Service ID is present in BPF map, updating revnat key") 494 revNATK, revNATV := lbmap.L3n4Addr2RevNatKeynValue( 495 loadbalancer.ServiceID(svc.FE.ID), revNAT) 496 err := lbmap.UpdateRevNat(revNATK, revNATV) 497 if err != nil { 498 return fmt.Errorf("Unable to add revNAT: %s: %s."+ 499 " This entry will be removed from the bpf's LB map.", revNAT.String(), err) 500 } 501 502 // Remove the old entry from the bpf map. 503 revNATK, _ = lbmap.L3n4Addr2RevNatKeynValue(oldID, revNAT) 504 if err := lbmap.DeleteRevNat(revNATK); err != nil { 505 scopedLog.WithError(err).Warn("Unable to remove old rev NAT entry") 506 } 507 508 scopedLog.Debug("deleting old ID from newRevNATMap") 509 delete(newRevNATMap, oldID) 510 511 log.WithFields(logrus.Fields{ 512 logfields.ServiceName: svc.FE.String(), 513 "revNAT": revNAT, 514 }).Debug("adding service --> revNAT to newRevNATMap") 515 newRevNATMap[loadbalancer.ServiceID(svc.FE.ID)] = revNAT 516 } 517 518 fe, besValues, err := lbmap.LBSVC2ServiceKeynValue(svc) 519 if err != nil { 520 return fmt.Errorf("Unable to create a BPF key and values for service FE: %s and backends: %+v. Error: %s."+ 521 " This entry will be removed from the bpf's LB map.", svc.FE.String(), svc.BES, err) 522 } 523 524 svcKeyV2, svcValuesV2, backendsV2, err := lbmap.LBSVC2ServiceKeynValuenBackendV2(&svc) 525 if err != nil { 526 return fmt.Errorf("Unable to create a BPF key and values for service v2 FE: %s and backends: %+v. Error: %s."+ 527 " This entry will be removed from the bpf's LB map.", svc.FE.String(), svc.BES, err) 528 } 529 530 err = d.addSVC2BPFMap(svc.FE, fe, besValues, svcKeyV2, svcValuesV2, backendsV2, false) 531 if err != nil { 532 return fmt.Errorf("Unable to add service FE: %s: %s."+ 533 " This entry will be removed from the bpf's LB map.", svc.FE.String(), err) 534 } 535 return nil 536 } 537 538 newSVCMap, newSVCList, lbmapDumpErrors := lbmap.DumpServiceMapsToUserspaceV2() 539 for _, err := range lbmapDumpErrors { 540 log.WithError(err).Warn("Unable to list services in services BPF map") 541 } 542 newRevNATMap, revNATMapDumpErrors := lbmap.DumpRevNATMapsToUserspace() 543 for _, err := range revNATMapDumpErrors { 544 log.WithError(err).Warn("Unable to list services in RevNat BPF map") 545 } 546 547 // Need to do this outside of parseSVCEntries to avoid deadlock, because we 548 // are modifying the BPF maps, and calling Dump on a Map RLocks the maps. 549 for _, svc := range newSVCList { 550 scopedLog := log.WithField(logfields.Object, logfields.Repr(svc)) 551 kvL3n4AddrID, err := service.RestoreID(svc.FE.L3n4Addr, uint32(svc.FE.ID)) 552 if err != nil { 553 scopedLog.WithError(err).Error("Unable to restore service ID") 554 failedSyncSVC = append(failedSyncSVC, *svc) 555 delete(newSVCMap, svc.Sha256) 556 // Don't update the maps of services since the service failed to 557 // sync. 558 continue 559 } 560 561 // Mismatch detected between BPF Maps and KVstore, so we need to update 562 // the ID in the BPF Maps to reflect the ID of the KVstore. 563 if svc.FE.ID != kvL3n4AddrID.ID { 564 scopedLog = scopedLog.WithField(logfields.ServiceID+".new", kvL3n4AddrID.ID) 565 scopedLog.WithError(err).Warning("Service ID in BPF map is out of sync with KVStore. Acquired new ID") 566 567 oldID := loadbalancer.ServiceID(svc.FE.ID) 568 svc.FE.ID = kvL3n4AddrID.ID 569 // If we cannot add the service to the BPF maps, update the list of 570 // services that failed to sync. 571 if err := addSVC2BPFMap(oldID, *svc); err != nil { 572 scopedLog.WithError(err).Error("Unable to synchronize service to BPF map") 573 574 failedSyncSVC = append(failedSyncSVC, *svc) 575 delete(newSVCMap, svc.Sha256) 576 577 revNAT, ok := newRevNATMap[loadbalancer.ServiceID(svc.FE.ID)] 578 if ok { 579 // Revert the old revNAT 580 newRevNATMap[oldID] = revNAT 581 failedSyncRevNAT[loadbalancer.ServiceID(svc.FE.ID)] = revNAT 582 delete(newRevNATMap, loadbalancer.ServiceID(svc.FE.ID)) 583 } 584 // Don't update the maps of services since the service failed to 585 // sync. 586 continue 587 } 588 } 589 newSVCMapID[loadbalancer.ServiceID(svc.FE.ID)] = svc 590 } 591 592 // Clean services and rev nats from BPF maps that failed to be restored. 593 for _, svc := range failedSyncSVC { 594 if err := d.svcDeleteBPF(svc.FE); err != nil { 595 log.WithError(err).WithField(logfields.Object, logfields.Repr(svc)). 596 Warn("Unable to remove unrestorable service from BPF map") 597 } 598 } 599 600 for id, revNAT := range failedSyncRevNAT { 601 var revNATK lbmap.RevNatKey 602 if !revNAT.IsIPv6() { 603 revNATK = lbmap.NewRevNat4Key(uint16(id)) 604 } else { 605 revNATK = lbmap.NewRevNat6Key(uint16(id)) 606 } 607 608 if err := lbmap.DeleteRevNat(revNATK); err != nil { 609 log.WithError(err).WithFields(logrus.Fields{ 610 logfields.ServiceID: id, 611 "revNAT": revNAT, 612 }).Warn("Unable to clean rev NAT from BPF map") 613 } 614 } 615 616 log.WithFields(logrus.Fields{ 617 "restoredServices": len(newSVCMap), 618 "restoredRevNat": len(newRevNATMap), 619 "failedServices": len(failedSyncSVC), 620 "failedRevNat": len(failedSyncRevNAT), 621 }).Info("Restored services from BPF maps") 622 623 d.loadBalancer.SVCMap = newSVCMap 624 d.loadBalancer.SVCMapID = newSVCMapID 625 d.loadBalancer.RevNATMap = newRevNATMap 626 627 return nil 628 } 629 630 // syncLBMapsWithK8s ensures that the only contents of all BPF maps related to 631 // services (loadbalancer, RevNAT - for IPv4 and IPv6) are those that are 632 // sent to Cilium via K8s. This function is intended to be ran as part of a 633 // controller by the daemon when bootstrapping, although it could be called 634 // elsewhere it needed. Returns an error if any issues occur dumping BPF maps 635 // or deleting entries from BPF maps. 636 func (d *Daemon) syncLBMapsWithK8s() error { 637 k8sDeletedServices := map[string]loadbalancer.L3n4AddrID{} 638 alreadyChecked := map[string]struct{}{} 639 640 // Maps service IDs to whether they are IPv6 (true) or IPv4 (false). 641 k8sDeletedRevNATS := make(map[loadbalancer.ServiceID]bool) 642 643 // Set of L3n4Addrs in string form for storage as a key in map. 644 k8sServicesFrontendAddresses := d.k8sSvcCache.UniqueServiceFrontends() 645 646 // NOTE: loadBalancer.BPFMapMU should be taken after k8sSvcCache.Mutex 647 // has been released, otherwise a deadlock can happen: See GH-8764. 648 d.loadBalancer.BPFMapMU.Lock() 649 defer d.loadBalancer.BPFMapMU.Unlock() 650 651 log.Debugf("dumping BPF service maps to userspace") 652 // At this point the creation of the v2 svc from the corresponding legacy 653 // one has already happened, so it's safe to rely on the v2 when dumping 654 _, newSVCList, lbmapDumpErrors := lbmap.DumpServiceMapsToUserspaceV2() 655 656 if len(lbmapDumpErrors) > 0 { 657 errorStrings := "" 658 for _, err := range lbmapDumpErrors { 659 errorStrings = fmt.Sprintf("%s, %s", err, errorStrings) 660 } 661 return fmt.Errorf("error(s): %s", errorStrings) 662 } 663 664 newRevNATMap, revNATMapDumpErrors := lbmap.DumpRevNATMapsToUserspace() 665 if len(revNATMapDumpErrors) > 0 { 666 errorStrings := "" 667 for _, err := range revNATMapDumpErrors { 668 errorStrings = fmt.Sprintf("%s, %s", err, errorStrings) 669 } 670 return fmt.Errorf("error(s): %s", errorStrings) 671 } 672 673 // Check whether services in service and revNAT BPF maps exist in the 674 // in-memory K8s service maps. If not, mark them for deletion. 675 for _, svc := range newSVCList { 676 id := svc.FE.L3n4Addr.StringWithProtocol() 677 if _, ok := alreadyChecked[id]; ok { 678 continue 679 } 680 681 alreadyChecked[id] = struct{}{} 682 683 scopedLog := log.WithFields(logrus.Fields{ 684 logfields.ServiceID: svc.FE.ID, 685 logfields.L3n4Addr: logfields.Repr(svc.FE.L3n4Addr)}) 686 687 if !k8sServicesFrontendAddresses.LooseMatch(svc.FE.L3n4Addr) { 688 scopedLog.Warning("Deleting no longer present service in datapath") 689 k8sDeletedServices[id] = svc.FE 690 continue 691 } 692 693 scopedLog.Debug("Found matching k8s service for service in BPF map") 694 } 695 696 for serviceID, serviceInfo := range newRevNATMap { 697 if _, ok := d.loadBalancer.RevNATMap[serviceID]; !ok { 698 log.WithFields(logrus.Fields{ 699 logfields.ServiceID: serviceID, 700 logfields.L3n4Addr: logfields.Repr(serviceInfo)}).Debug("revNAT ID read from BPF maps is not managed by K8s; will delete it from BPF maps") 701 // Map service ID to whether service is IPv4 or IPv6. 702 if serviceInfo.IP.To4() == nil { 703 k8sDeletedRevNATS[serviceID] = true 704 } else { 705 k8sDeletedRevNATS[serviceID] = false 706 } 707 } 708 } 709 710 bpfDeleteErrors := []error{} 711 712 // Delete map entries from BPF which don't exist in list of Kubernetes 713 // services. 714 for _, svc := range k8sDeletedServices { 715 svcLogger := log.WithField(logfields.Object, logfields.Repr(svc)) 716 svcLogger.Debug("removing service because it was not synced from Kubernetes") 717 if err := d.svcDeleteBPF(svc); err != nil { 718 bpfDeleteErrors = append(bpfDeleteErrors, err) 719 } 720 } 721 722 for serviceID, isIPv6 := range k8sDeletedRevNATS { 723 log.WithFields(logrus.Fields{logfields.ServiceID: serviceID, "isIPv6": isIPv6}).Debug("removing revNAT because it was not synced from Kubernetes") 724 if err := lbmap.DeleteRevNATBPF(serviceID, isIPv6); err != nil { 725 bpfDeleteErrors = append(bpfDeleteErrors, err) 726 } 727 } 728 729 if len(bpfDeleteErrors) > 0 { 730 bpfErrorsString := "" 731 for _, err := range bpfDeleteErrors { 732 bpfErrorsString = fmt.Sprintf("%s, %s", err, bpfErrorsString) 733 } 734 return fmt.Errorf("Errors deleting BPF map entries: %s", bpfErrorsString) 735 } 736 737 log.Debugf("successfully synced BPF loadbalancer and revNAT maps with in-memory Kubernetes service maps") 738 739 return nil 740 } 741 742 func restoreBackendIDs() (map[lbmap.BackendAddrID]lbmap.BackendKey, error) { 743 lbBackends, err := lbmap.DumpBackendMapsToUserspace() 744 if err != nil { 745 return nil, fmt.Errorf("Unable to dump LB backend maps: %s", err) 746 } 747 748 restoredBackendIDs := map[lbmap.BackendAddrID]lbmap.BackendKey{} 749 750 for addrID, lbBackend := range lbBackends { 751 err := service.RestoreBackendID(lbBackend.L3n4Addr, lbBackend.ID) 752 if err != nil { 753 return nil, err 754 } 755 be, err := lbmap.LBBackEnd2Backend(*lbBackend) 756 if err != nil { 757 return nil, err 758 } 759 restoredBackendIDs[addrID] = be.GetKey() 760 } 761 762 log.WithField(logfields.BackendIDs, restoredBackendIDs). 763 Debug("Restored backend IDs") 764 765 return restoredBackendIDs, nil 766 } 767 768 func restoreServices() { 769 before := time.Now() 770 771 // Restore Backend IDs first, otherwise they can get taken by subsequent 772 // calls to UpdateService 773 restoredBackendIDs, err := restoreBackendIDs() 774 if err != nil { 775 log.WithError(err).Warning("Error occurred while restoring backend IDs") 776 } 777 lbmap.AddBackendIDsToCache(restoredBackendIDs) 778 779 failed, restored, skipped, removed := 0, 0, 0, 0 780 svcIDs := make(map[loadbalancer.ID]struct{}) 781 782 svcMapV2, _, errors := lbmap.DumpServiceMapsToUserspaceV2() 783 for _, err := range errors { 784 log.WithError(err).Warning("Error occurred while dumping service v2 table from datapath") 785 } 786 787 for _, svc := range svcMapV2 { 788 scopedLog := log.WithFields(logrus.Fields{ 789 logfields.ServiceID: svc.FE.ID, 790 logfields.ServiceIP: svc.FE.L3n4Addr.String(), 791 }) 792 // Services where the service ID was missing in the BPF map 793 // cannot be restored 794 if uint32(svc.FE.ID) == uint32(0) { 795 skipped++ 796 continue 797 } 798 799 svcIDs[svc.FE.ID] = struct{}{} 800 801 // The service ID can only be restored when global service IDs 802 // are disabled. Global service IDs require kvstore access but 803 // service load-balancing needs to be enabled before the 804 // kvstore is guaranteed to be connected 805 if option.Config.LBInterface == "" { 806 _, err := service.RestoreID(svc.FE.L3n4Addr, uint32(svc.FE.ID)) 807 if err != nil { 808 failed++ 809 scopedLog.WithError(err).Warning("Unable to restore service ID from datapath") 810 } else { 811 restored++ 812 scopedLog.Debug("Restored service ID from datapath") 813 } 814 } 815 816 // Restore the service cache to guarantee backend ordering 817 // across restarts 818 if err := lbmap.RestoreService(svc); err != nil { 819 scopedLog.WithError(err).Warning("Unable to restore service in cache") 820 failed++ 821 continue 822 } 823 } 824 825 // Remove backend entries which are not used by any service. 826 if errs := lbmap.DeleteOrphanBackends(service.DeleteBackendID); errs != nil && len(errs) > 0 { 827 for _, err := range errs { 828 log.WithError(err).Warning("Unable to remove orphan backend") 829 } 830 } 831 832 log.WithFields(logrus.Fields{ 833 logfields.Duration: time.Now().Sub(before), 834 "restored": restored, 835 "failed": failed, 836 "skipped": skipped, 837 "removed": removed, 838 }).Info("Restore service IDs from BPF maps") 839 } 840 841 // GetServiceList returns list of services 842 func (d *Daemon) GetServiceList() []*models.Service { 843 list := []*models.Service{} 844 845 d.loadBalancer.BPFMapMU.RLock() 846 defer d.loadBalancer.BPFMapMU.RUnlock() 847 848 for _, v := range d.loadBalancer.SVCMap { 849 list = append(list, v.GetModel()) 850 } 851 return list 852 }