github.com/cilium/cilium@v1.16.2/pkg/identity/identitymanager/manager.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package identitymanager
     5  
     6  import (
     7  	"github.com/sirupsen/logrus"
     8  
     9  	"github.com/cilium/cilium/api/v1/models"
    10  	"github.com/cilium/cilium/pkg/identity"
    11  	"github.com/cilium/cilium/pkg/identity/model"
    12  	"github.com/cilium/cilium/pkg/lock"
    13  	"github.com/cilium/cilium/pkg/logging/logfields"
    14  )
    15  
    16  var (
    17  	// GlobalIdentityManager is a singleton instance of an IdentityManager, used
    18  	// for easy updating / tracking lifecycles of identities on the local node
    19  	// without having to pass around a specific instance of an IdentityManager
    20  	// throughout Cilium.
    21  	GlobalIdentityManager = NewIdentityManager()
    22  )
    23  
    24  // IdentityManager caches information about a set of identities, currently a
    25  // reference count of how many users there are for each identity.
    26  type IdentityManager struct {
    27  	mutex      lock.RWMutex
    28  	identities map[identity.NumericIdentity]*identityMetadata
    29  	observers  map[Observer]struct{}
    30  }
    31  
    32  type identityMetadata struct {
    33  	identity *identity.Identity
    34  	refCount uint
    35  }
    36  
    37  // NewIdentityManager returns an initialized IdentityManager.
    38  func NewIdentityManager() *IdentityManager {
    39  	return &IdentityManager{
    40  		identities: make(map[identity.NumericIdentity]*identityMetadata),
    41  		observers:  make(map[Observer]struct{}),
    42  	}
    43  }
    44  
    45  // Add inserts the identity into the GlobalIdentityManager.
    46  func Add(identity *identity.Identity) {
    47  	GlobalIdentityManager.Add(identity)
    48  }
    49  
    50  // Remove deletes the identity from the GlobalIdentityManager.
    51  func Remove(identity *identity.Identity) {
    52  	GlobalIdentityManager.Remove(identity)
    53  }
    54  
    55  // RemoveAll deletes all identities from the GlobalIdentityManager.
    56  func RemoveAll() {
    57  	GlobalIdentityManager.RemoveAll()
    58  }
    59  
    60  // Add inserts the identity into the identity manager. If the identity is
    61  // already in the identity manager, the reference count for the identity is
    62  // incremented.
    63  func (idm *IdentityManager) Add(identity *identity.Identity) {
    64  	log.WithFields(logrus.Fields{
    65  		logfields.Identity: identity,
    66  	}).Debug("Adding identity to the identity manager")
    67  
    68  	idm.mutex.Lock()
    69  	defer idm.mutex.Unlock()
    70  	idm.add(identity)
    71  }
    72  
    73  func (idm *IdentityManager) add(identity *identity.Identity) {
    74  
    75  	if identity == nil {
    76  		return
    77  	}
    78  
    79  	idMeta, exists := idm.identities[identity.ID]
    80  	if !exists {
    81  		idm.identities[identity.ID] = &identityMetadata{
    82  			identity: identity,
    83  			refCount: 1,
    84  		}
    85  		for o := range idm.observers {
    86  			o.LocalEndpointIdentityAdded(identity)
    87  		}
    88  
    89  	} else {
    90  		idMeta.refCount++
    91  	}
    92  }
    93  
    94  // RemoveOldAddNew removes old from the identity manager and inserts new
    95  // into the IdentityManager.
    96  // Caller must have previously added the old identity with Add().
    97  // This is a no-op if both identities have the same numeric ID.
    98  func (idm *IdentityManager) RemoveOldAddNew(old, new *identity.Identity) {
    99  	idm.mutex.Lock()
   100  	defer idm.mutex.Unlock()
   101  
   102  	if old == nil && new == nil {
   103  		return
   104  	}
   105  	// The host endpoint will always retain its reserved ID, but its labels may
   106  	// change so we need to update its identity.
   107  	if old != nil && new != nil && old.ID == new.ID && new.ID != identity.ReservedIdentityHost {
   108  		return
   109  	}
   110  
   111  	log.WithFields(logrus.Fields{
   112  		"old": old,
   113  		"new": new,
   114  	}).Debug("removing old and adding new identity")
   115  
   116  	idm.remove(old)
   117  	idm.add(new)
   118  }
   119  
   120  // RemoveOldAddNew removes old from and inserts new into the
   121  // GlobalIdentityManager.
   122  func RemoveOldAddNew(old, new *identity.Identity) {
   123  	GlobalIdentityManager.RemoveOldAddNew(old, new)
   124  }
   125  
   126  // RemoveAll removes all identities.
   127  func (idm *IdentityManager) RemoveAll() {
   128  	idm.mutex.Lock()
   129  	defer idm.mutex.Unlock()
   130  
   131  	for id := range idm.identities {
   132  		idm.remove(idm.identities[id].identity)
   133  	}
   134  }
   135  
   136  // Remove deletes the identity from the identity manager. If the identity is
   137  // already in the identity manager, the reference count for the identity is
   138  // decremented. If the identity is not in the cache, this is a no-op. If the
   139  // ref count becomes zero, the identity is removed from the cache.
   140  func (idm *IdentityManager) Remove(identity *identity.Identity) {
   141  	log.WithFields(logrus.Fields{
   142  		logfields.Identity: identity,
   143  	}).Debug("Removing identity from the identity manager")
   144  
   145  	idm.mutex.Lock()
   146  	defer idm.mutex.Unlock()
   147  	idm.remove(identity)
   148  }
   149  
   150  func (idm *IdentityManager) remove(identity *identity.Identity) {
   151  
   152  	if identity == nil {
   153  		return
   154  	}
   155  
   156  	idMeta, exists := idm.identities[identity.ID]
   157  	if !exists {
   158  		log.WithFields(logrus.Fields{
   159  			logfields.Identity: identity,
   160  		}).Error("removing identity not added to the identity manager!")
   161  		return
   162  	}
   163  	idMeta.refCount--
   164  	if idMeta.refCount == 0 {
   165  		delete(idm.identities, identity.ID)
   166  		for o := range idm.observers {
   167  			o.LocalEndpointIdentityRemoved(identity)
   168  		}
   169  	}
   170  
   171  }
   172  
   173  // GetIdentityModels returns the API representation of the IdentityManager.
   174  func (idm *IdentityManager) GetIdentityModels() []*models.IdentityEndpoints {
   175  	idm.mutex.RLock()
   176  	defer idm.mutex.RUnlock()
   177  
   178  	identities := make([]*models.IdentityEndpoints, 0, len(idm.identities))
   179  
   180  	for _, v := range idm.identities {
   181  		identities = append(identities, &models.IdentityEndpoints{
   182  			Identity: model.CreateModel(v.identity),
   183  			RefCount: int64(v.refCount),
   184  		})
   185  	}
   186  
   187  	return identities
   188  }
   189  
   190  func (idm *IdentityManager) subscribe(o Observer) {
   191  	idm.mutex.Lock()
   192  	defer idm.mutex.Unlock()
   193  	idm.observers[o] = struct{}{}
   194  }
   195  
   196  // GetIdentityModels returns the API model of all identities in the
   197  // GlobalIdentityManager.
   198  func GetIdentityModels() []*models.IdentityEndpoints {
   199  	return GlobalIdentityManager.GetIdentityModels()
   200  }
   201  
   202  // IdentitiesModel is a wrapper so that we can implement the sort.Interface
   203  // to sort the slice by ID
   204  type IdentitiesModel []*models.IdentityEndpoints
   205  
   206  // Less returns true if the element in index `i` is lower than the element
   207  // in index `j`
   208  func (s IdentitiesModel) Less(i, j int) bool {
   209  	return s[i].Identity.ID < s[j].Identity.ID
   210  }
   211  
   212  // Subscribe adds the specified Observer to the global identity manager, to be
   213  // notified upon changes to local identity usage.
   214  func Subscribe(o Observer) {
   215  	GlobalIdentityManager.subscribe(o)
   216  }