github.com/cilium/cilium@v1.16.2/pkg/bgpv1/manager/state_tracker.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package manager 5 6 import ( 7 "context" 8 "errors" 9 10 "github.com/cilium/cilium/pkg/bgpv1/manager/reconcilerv2" 11 "github.com/cilium/cilium/pkg/bgpv1/types" 12 ) 13 14 var ( 15 ErrInstanceDoesNotExist = errors.New("instance does not exist") 16 ) 17 18 // trackInstanceStateChange should be started as a goroutine. It listens on the tracker channel 19 // and signals state reconciler. It will be returned when tracker go routine is closed. 20 func (m *BGPRouterManager) trackInstanceStateChange(instance string, tracker chan struct{}) { 21 for range tracker { 22 m.Logger.WithField(types.InstanceLogField, instance).Debug("Event change detected for instance") 23 24 // insert this instance in pending state modified list 25 // we can be waiting here for long since lock is also taken by main reconcile loop. 26 // We do not want to modify PendingInstances set while main reconcile loop is processing it. 27 // Any new events will level trigger tracker channel and move along. 28 m.state.pendingInstancesMutex.Lock() 29 m.state.pendingInstances.Insert(instance) 30 m.state.pendingInstancesMutex.Unlock() 31 32 // notify the main reconcile loop that the state for some instance has changed 33 // It is okay if that channel is full, there can be multiple instances trying to 34 // notify the main reconcile loop that the state has changed. 35 select { 36 case m.state.reconcileSignal <- struct{}{}: 37 default: 38 } 39 } 40 41 // tracker is closed, signal the main reconcile loop that this instance is deleted so it 42 // can do any necessary cleanup. 43 m.state.instanceDeletionSignal <- instance 44 m.Logger.WithField(types.InstanceLogField, instance).Debug("Instance deleted, stopping state tracker") 45 } 46 47 // reconcileState is the main loop that reconciles the state of all instances that have pending state changes. 48 // It will take StateMutex lock to process the pending instances and remove them from the pending instances set. 49 // Any new state changes will be blocked till this method completes. 50 func (m *BGPRouterManager) reconcileState(ctx context.Context) error { 51 var allErrs error 52 53 // we lock the state mutex so no changes to PendingInstances set can be made while we are processing it. 54 m.state.pendingInstancesMutex.Lock() 55 defer m.state.pendingInstancesMutex.Unlock() 56 57 m.Logger.WithField("UpdatedInstances", m.state.pendingInstances.Len()). 58 Debug("Reconciling state for instances with pending state changes") 59 60 // process all pending instances, failed instances will be retried in next reconcile loop. 61 for instanceName := range m.state.pendingInstances { 62 err := m.reconcileInstanceState(ctx, instanceName) 63 if err != nil && !errors.Is(err, ErrInstanceDoesNotExist) { 64 allErrs = errors.Join(allErrs, err) 65 } else { 66 m.state.pendingInstances.Delete(instanceName) 67 } 68 } 69 70 return allErrs 71 } 72 73 func (m *BGPRouterManager) reconcileInstanceDeletion(ctx context.Context, instanceName string) { 74 m.RLock() 75 defer m.RUnlock() 76 77 for _, stateReconciler := range m.state.reconcilers { 78 err := stateReconciler.Reconcile(ctx, reconcilerv2.StateReconcileParams{ 79 ConfigMode: m.ConfigMode, 80 DeletedInstance: instanceName, 81 }) 82 if err != nil { 83 m.Logger.WithError(err). 84 WithField(types.InstanceLogField, instanceName). 85 Error("Error while reconciling state") 86 } 87 } 88 } 89 90 // reconcileInstanceState reconciles the state of a single instance. It will take read lock 91 // on BGPInstances lock as we are inspecting BGP instances. 92 // It will call all the state reconcilers to reconcile the state of the instance. 93 func (m *BGPRouterManager) reconcileInstanceState(ctx context.Context, instanceName string) error { 94 m.RLock() 95 defer m.RUnlock() 96 97 instance, exists := m.BGPInstances[instanceName] 98 if !exists { 99 return ErrInstanceDoesNotExist 100 } 101 102 var err error 103 for _, stateReconciler := range m.state.reconcilers { 104 err = errors.Join(err, stateReconciler.Reconcile(ctx, reconcilerv2.StateReconcileParams{ 105 ConfigMode: m.ConfigMode, 106 UpdatedInstance: instance, 107 })) 108 } 109 110 return err 111 }