github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/maps/lbmap/lbmap.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 lbmap
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/cilium/cilium/pkg/bpf"
    21  	"github.com/cilium/cilium/pkg/loadbalancer"
    22  	"github.com/cilium/cilium/pkg/lock"
    23  	"github.com/cilium/cilium/pkg/logging"
    24  	"github.com/cilium/cilium/pkg/logging/logfields"
    25  	"github.com/cilium/cilium/pkg/option"
    26  	"github.com/cilium/cilium/pkg/u8proto"
    27  
    28  	"github.com/sirupsen/logrus"
    29  )
    30  
    31  var (
    32  	log = logging.DefaultLogger.WithField(logfields.LogSubsys, "map-lb")
    33  
    34  	// mutex protects access to the BPF map to guarantee atomicity if a
    35  	// transaction must be split across multiple map access operations.
    36  	mutex lock.RWMutex
    37  )
    38  
    39  const (
    40  	// Maximum number of entries in each hashtable
    41  	MaxEntries   = 65536
    42  	maxFrontEnds = 256
    43  	// MaxSeq is used by daemon for generating bpf define LB_RR_MAX_SEQ.
    44  	MaxSeq = 31
    45  )
    46  
    47  var (
    48  	// cache contains *all* services of both IPv4 and IPv6 based maps
    49  	// combined
    50  	cache = newLBMapCache()
    51  )
    52  
    53  func updateRevNatLocked(key RevNatKey, value RevNatValue) error {
    54  	log.WithFields(logrus.Fields{
    55  		logfields.BPFMapKey:   key,
    56  		logfields.BPFMapValue: value,
    57  	}).Debug("adding revNat to lbmap")
    58  
    59  	if key.GetKey() == 0 {
    60  		return fmt.Errorf("invalid RevNat ID (0)")
    61  	}
    62  	if _, err := key.Map().OpenOrCreate(); err != nil {
    63  		return err
    64  	}
    65  
    66  	return key.Map().Update(key.ToNetwork(), value.ToNetwork())
    67  }
    68  
    69  func UpdateRevNat(key RevNatKey, value RevNatValue) error {
    70  	mutex.Lock()
    71  	defer mutex.Unlock()
    72  
    73  	return updateRevNatLocked(key, value)
    74  }
    75  
    76  func deleteRevNatLocked(key RevNatKey) error {
    77  	log.WithField(logfields.BPFMapKey, key).Debug("deleting RevNatKey")
    78  
    79  	return key.Map().Delete(key.ToNetwork())
    80  }
    81  
    82  func DeleteRevNat(key RevNatKey) error {
    83  	mutex.Lock()
    84  	defer mutex.Unlock()
    85  
    86  	return deleteRevNatLocked(key)
    87  }
    88  
    89  // gcd computes the gcd of two numbers.
    90  func gcd(x, y uint16) uint16 {
    91  	for y != 0 {
    92  		x, y = y, x%y
    93  	}
    94  	return x
    95  }
    96  
    97  // generateWrrSeq generates a wrr sequence based on provided weights.
    98  func generateWrrSeq(weights []uint16) (*RRSeqValue, error) {
    99  	svcRRSeq := RRSeqValue{}
   100  
   101  	n := len(weights)
   102  	if n < 2 {
   103  		return nil, fmt.Errorf("needs at least 2 weights")
   104  	}
   105  
   106  	g := uint16(0)
   107  	for i := 0; i < n; i++ {
   108  		if weights[i] != 0 {
   109  			g = gcd(g, weights[i])
   110  		}
   111  	}
   112  
   113  	// This means all the weights are 0.
   114  	if g == 0 {
   115  		return nil, fmt.Errorf("all specified weights are 0")
   116  	}
   117  
   118  	sum := uint16(0)
   119  	for i := range weights {
   120  		// Normalize the weights.
   121  		weights[i] = weights[i] / g
   122  		sum += weights[i]
   123  	}
   124  
   125  	// Check if Generated seq fits in our array.
   126  	if int(sum) > len(svcRRSeq.Idx) {
   127  		return nil, fmt.Errorf("sum of normalized weights exceeds %d", len(svcRRSeq.Idx))
   128  	}
   129  
   130  	// Generate the Sequence.
   131  	i := uint16(0)
   132  	k := uint16(0)
   133  	for {
   134  		j := uint16(0)
   135  		for j < weights[k] {
   136  			svcRRSeq.Idx[i] = k
   137  			i++
   138  			j++
   139  		}
   140  		if i >= sum {
   141  			break
   142  		}
   143  		k++
   144  	}
   145  	svcRRSeq.Count = sum
   146  	return &svcRRSeq, nil
   147  }
   148  
   149  // UpdateService adds or updates the given service in the bpf maps.
   150  func UpdateService(fe ServiceKey, backends []ServiceValue,
   151  	addRevNAT bool, revNATID int,
   152  	acquireBackendID func(loadbalancer.L3n4Addr) (loadbalancer.BackendID, error),
   153  	releaseBackendID func(loadbalancer.BackendID)) error {
   154  
   155  	scopedLog := log.WithFields(logrus.Fields{
   156  		"frontend": fe,
   157  		"backends": backends,
   158  	})
   159  
   160  	mutex.Lock()
   161  	defer mutex.Unlock()
   162  
   163  	var (
   164  		weights         []uint16
   165  		nNonZeroWeights uint16
   166  	)
   167  
   168  	// Find out which backends are new (i.e. the ones which do not exist yet and
   169  	// will be created in this function) and acquire IDs for them
   170  	newBackendIDs, err := acquireNewBackendIDs(backends, acquireBackendID)
   171  	if err != nil {
   172  		return err
   173  	}
   174  
   175  	// Store mapping of backend addr ID => backend ID in the cache
   176  	cache.addBackendIDs(newBackendIDs)
   177  
   178  	// Prepare the service cache for the updates
   179  	svc, addedBackends, removedBackendIDs, err := cache.prepareUpdate(fe, backends)
   180  	if err != nil {
   181  		return err
   182  	}
   183  
   184  	// FIXME(brb) Uncomment the following code after we have enabled weights
   185  	// in the BPF datapath code.
   186  	//for _, be := range besValues {
   187  	//	weights = append(weights, be.GetWeight())
   188  	//	if be.GetWeight() != 0 {
   189  	//		nNonZeroWeights++
   190  	//	}
   191  	//}
   192  
   193  	besValuesV2 := svc.getBackendsV2()
   194  
   195  	scopedLog.Debug("Updating BPF representation of service")
   196  
   197  	// Add the new backends to the BPF maps
   198  	if err := updateBackendsLocked(addedBackends); err != nil {
   199  		return err
   200  	}
   201  
   202  	// Update the v2 service BPF maps
   203  	if err := updateServiceV2Locked(fe, besValuesV2, svc, addRevNAT, revNATID, weights, nNonZeroWeights); err != nil {
   204  		return err
   205  	}
   206  
   207  	// Delete no longer needed backends
   208  	if err := removeBackendsLocked(removedBackendIDs, releaseBackendID); err != nil {
   209  		return err
   210  	}
   211  
   212  	return nil
   213  }
   214  
   215  func acquireNewBackendIDs(backends []ServiceValue,
   216  	acquireBackendID func(loadbalancer.L3n4Addr) (loadbalancer.BackendID, error)) (
   217  	map[BackendAddrID]BackendKey, error) {
   218  
   219  	newBackendsByAddrID := serviceValueMap{}
   220  	for _, b := range backends {
   221  		newBackendsByAddrID[b.BackendAddrID()] = b
   222  	}
   223  	newBackendsByAddrID = cache.filterNewBackends(newBackendsByAddrID)
   224  	newBackendIDs := map[BackendAddrID]BackendKey{}
   225  
   226  	for addrID, value := range newBackendsByAddrID {
   227  		addr := *serviceValue2L3n4Addr(newBackendsByAddrID[addrID])
   228  		backendID, err := acquireBackendID(addr)
   229  		if err != nil {
   230  			return nil, fmt.Errorf("Unable to acquire backend ID for %s: %s", addrID, err)
   231  		}
   232  		if value.IsIPv6() {
   233  			newBackendIDs[addrID] = NewBackend6Key(backendID)
   234  		} else {
   235  			newBackendIDs[addrID] = NewBackend4Key(backendID)
   236  		}
   237  		log.WithFields(logrus.Fields{
   238  			logfields.BackendName: addrID,
   239  			logfields.BackendID:   backendID,
   240  		}).Debug("Acquired backend ID")
   241  	}
   242  	return newBackendIDs, nil
   243  }
   244  
   245  func updateBackendsLocked(addedBackends map[loadbalancer.BackendID]ServiceValue) error {
   246  	var err error
   247  
   248  	// Create new backends
   249  	for backendID, svcVal := range addedBackends {
   250  		var b Backend
   251  
   252  		if svcVal.IsIPv6() {
   253  			svc6Val := svcVal.(*Service6Value)
   254  			b, err = NewBackend6(backendID, svc6Val.Address.IP(), svc6Val.Port, u8proto.ANY)
   255  		} else {
   256  			svc4Val := svcVal.(*Service4Value)
   257  			b, err = NewBackend4(backendID, svc4Val.Address.IP(), svc4Val.Port, u8proto.ANY)
   258  		}
   259  		if err != nil {
   260  			return err
   261  		}
   262  		if err := updateBackend(b); err != nil {
   263  			return err
   264  		}
   265  	}
   266  	return nil
   267  
   268  }
   269  
   270  func updateServiceV2Locked(fe ServiceKey, backends serviceValueMap,
   271  	svc *bpfService,
   272  	addRevNAT bool, revNATID int,
   273  	weights []uint16, nNonZeroWeights uint16) error {
   274  
   275  	var (
   276  		existingCount int
   277  		svcKeyV2      ServiceKeyV2
   278  	)
   279  
   280  	if fe.IsIPv6() {
   281  		svc6Key := fe.(*Service6Key)
   282  		svcKeyV2 = NewService6KeyV2(svc6Key.Address.IP(), svc6Key.Port, u8proto.ANY, 0)
   283  	} else {
   284  		svc4Key := fe.(*Service4Key)
   285  		svcKeyV2 = NewService4KeyV2(svc4Key.Address.IP(), svc4Key.Port, u8proto.ANY, 0)
   286  	}
   287  
   288  	svcValV2, err := lookupServiceV2(svcKeyV2)
   289  	if err == nil {
   290  		existingCount = svcValV2.GetCount()
   291  	}
   292  
   293  	svcValV2 = svcKeyV2.NewValue().(ServiceValueV2)
   294  	slot := 1
   295  	for addrID, svcVal := range backends {
   296  		backendKey := cache.getBackendKey(addrID)
   297  		svcValV2.SetBackendID(backendKey.GetID())
   298  		svcValV2.SetRevNat(revNATID)
   299  		svcValV2.SetWeight(svcVal.GetWeight())
   300  		svcKeyV2.SetSlave(slot)
   301  		if err := updateServiceEndpointV2(svcKeyV2, svcValV2); err != nil {
   302  			return fmt.Errorf("Unable to update service %+v with the value %+v: %s",
   303  				svcKeyV2, svcValV2, err)
   304  		}
   305  		log.WithFields(logrus.Fields{
   306  			logfields.ServiceKey:   svcKeyV2,
   307  			logfields.ServiceValue: svcValV2,
   308  			logfields.SlaveSlot:    slot,
   309  		}).Debug("Upserted service entry")
   310  		slot++
   311  	}
   312  
   313  	if addRevNAT {
   314  		zeroValue := fe.NewValue().(ServiceValue)
   315  		zeroValue.SetRevNat(revNATID)
   316  		revNATKey := zeroValue.RevNatKey()
   317  		revNATValue := fe.RevNatValue()
   318  
   319  		if err := updateRevNatLocked(revNATKey, revNATValue); err != nil {
   320  			return fmt.Errorf("unable to update reverse NAT %+v with value %+v, %s", revNATKey, revNATValue, err)
   321  		}
   322  		defer func() {
   323  			if err != nil {
   324  				deleteRevNatLocked(revNATKey)
   325  			}
   326  		}()
   327  	}
   328  
   329  	err = updateMasterServiceV2(svcKeyV2, len(svc.backendsV2), nNonZeroWeights, revNATID)
   330  	if err != nil {
   331  		return fmt.Errorf("unable to update service %+v: %s", svcKeyV2, err)
   332  	}
   333  
   334  	err = updateWrrSeqV2(svcKeyV2, weights)
   335  	if err != nil {
   336  		return fmt.Errorf("unable to update service weights for %s with value %+v: %s", svcKeyV2.String(), weights, err)
   337  	}
   338  
   339  	for i := slot; i <= existingCount; i++ {
   340  		svcKeyV2.SetSlave(i)
   341  		if err := deleteServiceLockedV2(svcKeyV2); err != nil {
   342  			return fmt.Errorf("unable to delete service %+v: %s", svcKeyV2, err)
   343  		}
   344  		log.WithFields(logrus.Fields{
   345  			logfields.SlaveSlot:  i,
   346  			logfields.ServiceKey: svcKeyV2,
   347  		}).Debug("Deleted service entry")
   348  	}
   349  
   350  	return nil
   351  }
   352  
   353  func removeBackendsLocked(removedBackendIDs []BackendKey,
   354  	releaseBackendID func(loadbalancer.BackendID)) error {
   355  
   356  	for _, backendKey := range removedBackendIDs {
   357  		if err := deleteBackendLocked(backendKey); err != nil {
   358  			return fmt.Errorf("Unable to delete backend with ID %d: %s", backendKey, err)
   359  		}
   360  		releaseBackendID(backendKey.GetID())
   361  		log.WithField(logfields.BackendID, backendKey).Debug("Deleted backend")
   362  	}
   363  
   364  	return nil
   365  }
   366  
   367  // DeleteRevNATBPF deletes the revNAT entry from its corresponding BPF map
   368  // (IPv4 or IPv6) with ID id. Returns an error if the deletion operation failed.
   369  func DeleteRevNATBPF(id loadbalancer.ServiceID, isIPv6 bool) error {
   370  	var revNATK RevNatKey
   371  	if isIPv6 {
   372  		revNATK = NewRevNat6Key(uint16(id))
   373  	} else {
   374  		revNATK = NewRevNat4Key(uint16(id))
   375  	}
   376  	err := DeleteRevNat(revNATK)
   377  	return err
   378  }
   379  
   380  // DumpServiceMapsToUserspaceV2 dumps the services in the same way as
   381  // DumpServiceMapsToUserspace.
   382  func DumpServiceMapsToUserspaceV2() (loadbalancer.SVCMap, []*loadbalancer.LBSVC, []error) {
   383  	mutex.RLock()
   384  	defer mutex.RUnlock()
   385  
   386  	newSVCMap := loadbalancer.SVCMap{}
   387  	newSVCList := []*loadbalancer.LBSVC{}
   388  	errors := []error{}
   389  	idCache := map[string]loadbalancer.ServiceID{}
   390  	backendValueMap := map[loadbalancer.BackendID]BackendValue{}
   391  
   392  	parseBackendEntries := func(key bpf.MapKey, value bpf.MapValue) {
   393  		backendKey := key.(BackendKey)
   394  		backendValue := value.DeepCopyMapValue().(BackendValue)
   395  		backendValueMap[backendKey.GetID()] = backendValue
   396  	}
   397  
   398  	parseSVCEntries := func(key bpf.MapKey, value bpf.MapValue) {
   399  		svcKey := key.DeepCopyMapKey().(ServiceKeyV2)
   400  		svcValue := value.DeepCopyMapValue().(ServiceValueV2)
   401  
   402  		// Skip master service
   403  		if svcKey.GetSlave() == 0 {
   404  			return
   405  		}
   406  
   407  		backendID := svcValue.GetBackendID()
   408  
   409  		scopedLog := log.WithFields(logrus.Fields{
   410  			logfields.BPFMapKey:   svcKey,
   411  			logfields.BPFMapValue: svcValue,
   412  		})
   413  
   414  		backendValue, found := backendValueMap[backendID]
   415  		if !found {
   416  			errors = append(errors, fmt.Errorf("backend %d not found", backendID))
   417  			return
   418  		}
   419  
   420  		scopedLog.Debug("parsing service mapping v2")
   421  		fe, be := serviceKeynValuenBackendValue2FEnBE(svcKey, svcValue, backendID, backendValue)
   422  
   423  		// Build a cache to map frontend IP to service ID. The master
   424  		// service key does not have the service ID set so the cache
   425  		// needs to be built based on backend key entries.
   426  		if k := svcValue.RevNatKey().GetKey(); k != uint16(0) {
   427  			idCache[fe.String()] = loadbalancer.ServiceID(k)
   428  		}
   429  
   430  		svc := newSVCMap.AddFEnBE(fe, be, svcKey.GetSlave())
   431  		newSVCList = append(newSVCList, svc)
   432  	}
   433  
   434  	if option.Config.EnableIPv4 {
   435  		// TODO(brb) optimization: instead of dumping the backend map, we can
   436  		// pass its content to the function.
   437  		err := Backend4Map.DumpWithCallback(parseBackendEntries)
   438  		if err != nil {
   439  			errors = append(errors, err)
   440  		}
   441  		err = Service4MapV2.DumpWithCallback(parseSVCEntries)
   442  		if err != nil {
   443  			errors = append(errors, err)
   444  		}
   445  	}
   446  
   447  	if option.Config.EnableIPv6 {
   448  		// TODO(brb) same ^^ optimization applies here as well.
   449  		err := Backend6Map.DumpWithCallback(parseBackendEntries)
   450  		if err != nil {
   451  			errors = append(errors, err)
   452  		}
   453  		err = Service6MapV2.DumpWithCallback(parseSVCEntries)
   454  		if err != nil {
   455  			errors = append(errors, err)
   456  		}
   457  	}
   458  
   459  	// serviceKeynValue2FEnBE() cannot fill in the service ID reliably as
   460  	// not all BPF map entries contain the service ID. Do a pass over all
   461  	// parsed entries and fill in the service ID
   462  	for i := range newSVCList {
   463  		newSVCList[i].FE.ID = loadbalancer.ID(idCache[newSVCList[i].FE.String()])
   464  	}
   465  
   466  	// Do the same for the svcMap
   467  	for key, svc := range newSVCMap {
   468  		svc.FE.ID = loadbalancer.ID(idCache[svc.FE.String()])
   469  		newSVCMap[key] = svc
   470  	}
   471  
   472  	return newSVCMap, newSVCList, errors
   473  }
   474  
   475  // DumpBackendMapsToUserspace dumps the backend entries from the BPF maps.
   476  func DumpBackendMapsToUserspace() (map[BackendAddrID]*loadbalancer.LBBackEnd, error) {
   477  	mutex.RLock()
   478  	defer mutex.RUnlock()
   479  
   480  	backendValueMap := map[loadbalancer.BackendID]BackendValue{}
   481  	lbBackends := map[BackendAddrID]*loadbalancer.LBBackEnd{}
   482  
   483  	parseBackendEntries := func(key bpf.MapKey, value bpf.MapValue) {
   484  		// No need to deep copy the key because we are using the ID which
   485  		// is a value.
   486  		backendKey := key.(BackendKey)
   487  		backendValue := value.DeepCopyMapValue().(BackendValue)
   488  		backendValueMap[backendKey.GetID()] = backendValue
   489  	}
   490  
   491  	if option.Config.EnableIPv4 {
   492  		err := Backend4Map.DumpWithCallback(parseBackendEntries)
   493  		if err != nil {
   494  			return nil, fmt.Errorf("Unable to dump lb4 backends map: %s", err)
   495  		}
   496  	}
   497  
   498  	if option.Config.EnableIPv6 {
   499  		err := Backend6Map.DumpWithCallback(parseBackendEntries)
   500  		if err != nil {
   501  			return nil, fmt.Errorf("Unable to dump lb6 backends map: %s", err)
   502  		}
   503  	}
   504  
   505  	for backendID, backendVal := range backendValueMap {
   506  		ip := backendVal.GetAddress()
   507  		port := backendVal.GetPort()
   508  		weight := uint16(0) // FIXME(brb): set weight when we support it
   509  		proto := loadbalancer.NONE
   510  		lbBackend := loadbalancer.NewLBBackEnd(backendID, proto, ip, port, weight)
   511  		lbBackends[backendVal.BackendAddrID()] = lbBackend
   512  	}
   513  
   514  	return lbBackends, nil
   515  }
   516  
   517  // DumpRevNATMapsToUserspace dumps the contents of both the IPv6 and IPv4
   518  // revNAT BPF maps, and stores the contents of said dumps in a RevNATMap.
   519  // Returns the errors that occurred while dumping the maps.
   520  func DumpRevNATMapsToUserspace() (loadbalancer.RevNATMap, []error) {
   521  	mutex.RLock()
   522  	defer mutex.RUnlock()
   523  
   524  	newRevNATMap := loadbalancer.RevNATMap{}
   525  	errors := []error{}
   526  
   527  	parseRevNATEntries := func(key bpf.MapKey, value bpf.MapValue) {
   528  		revNatK := key.DeepCopyMapKey().(RevNatKey)
   529  		revNatV := value.DeepCopyMapValue().(RevNatValue)
   530  		scopedLog := log.WithFields(logrus.Fields{
   531  			logfields.BPFMapKey:   revNatK,
   532  			logfields.BPFMapValue: revNatV,
   533  		})
   534  
   535  		scopedLog.Debug("parsing BPF revNAT mapping")
   536  		fe := revNatValue2L3n4AddrID(revNatK, revNatV)
   537  		newRevNATMap[loadbalancer.ServiceID(fe.ID)] = fe.L3n4Addr
   538  	}
   539  
   540  	if option.Config.EnableIPv4 {
   541  		if err := RevNat4Map.DumpWithCallback(parseRevNATEntries); err != nil {
   542  			err = fmt.Errorf("error dumping RevNat4Map: %s", err)
   543  			errors = append(errors, err)
   544  		}
   545  	}
   546  
   547  	if option.Config.EnableIPv6 {
   548  		if err := RevNat6Map.DumpWithCallback(parseRevNATEntries); err != nil {
   549  			err = fmt.Errorf("error dumping RevNat6Map: %s", err)
   550  			errors = append(errors, err)
   551  		}
   552  	}
   553  
   554  	return newRevNATMap, errors
   555  }
   556  
   557  // RestoreService restores a single service in the cache. This is required to
   558  // guarantee consistent backend ordering, slave slot and backend by backend
   559  // address ID lookups.
   560  func RestoreService(svc loadbalancer.LBSVC) error {
   561  	mutex.Lock()
   562  	defer mutex.Unlock()
   563  
   564  	return cache.restoreService(svc)
   565  }
   566  
   567  func lookupServiceV2(key ServiceKeyV2) (ServiceValueV2, error) {
   568  	val, err := key.Map().Lookup(key.ToNetwork())
   569  	if err != nil {
   570  		return nil, err
   571  	}
   572  	svc := val.(ServiceValueV2)
   573  
   574  	return svc.ToNetwork(), nil
   575  }
   576  
   577  func updateMasterServiceV2(fe ServiceKeyV2, nbackends int, nonZeroWeights uint16, revNATID int) error {
   578  	fe.SetSlave(0)
   579  	zeroValue := fe.NewValue().(ServiceValueV2)
   580  	zeroValue.SetCount(nbackends)
   581  	zeroValue.SetWeight(nonZeroWeights)
   582  	zeroValue.SetRevNat(revNATID)
   583  
   584  	return updateServiceEndpointV2(fe, zeroValue)
   585  }
   586  
   587  // updateWrrSeq updates bpf map with the generated wrr sequence.
   588  func updateWrrSeqV2(fe ServiceKeyV2, weights []uint16) error {
   589  	sum := uint16(0)
   590  	for _, v := range weights {
   591  		sum += v
   592  	}
   593  	if sum == 0 {
   594  		return nil
   595  	}
   596  	svcRRSeq, err := generateWrrSeq(weights)
   597  	if err != nil {
   598  		return fmt.Errorf("unable to generate weighted round robin seq for %s with value %+v: %s", fe.String(), weights, err)
   599  	}
   600  	return updateServiceWeightsV2(fe, svcRRSeq)
   601  }
   602  
   603  // updateServiceWeightsV2 updates cilium_lb6_rr_seq_v2 or cilium_lb4_rr_seq_v2 bpf maps.
   604  func updateServiceWeightsV2(key ServiceKeyV2, value *RRSeqValue) error {
   605  	if _, err := key.RRMap().OpenOrCreate(); err != nil {
   606  		return err
   607  	}
   608  
   609  	return key.RRMap().Update(key.ToNetwork(), value)
   610  }
   611  
   612  func deleteServiceLockedV2(key ServiceKeyV2) error {
   613  	err := key.Map().Delete(key.ToNetwork())
   614  	if err != nil {
   615  		return err
   616  	}
   617  	return lookupAndDeleteServiceWeightsV2(key)
   618  }
   619  
   620  // lookupAndDeleteServiceWeightsV2 deletes entry from cilium_lb6_rr_seq or cilium_lb4_rr_seq
   621  func lookupAndDeleteServiceWeightsV2(key ServiceKeyV2) error {
   622  	_, err := key.RRMap().Lookup(key.ToNetwork())
   623  	if err != nil {
   624  		// Ignore if entry is not found.
   625  		return nil
   626  	}
   627  
   628  	return key.RRMap().Delete(key.ToNetwork())
   629  }
   630  
   631  func updateBackend(backend Backend) error {
   632  	if _, err := backend.Map().OpenOrCreate(); err != nil {
   633  		return err
   634  	}
   635  	return backend.Map().Update(backend.GetKey(), backend.GetValue().ToNetwork())
   636  }
   637  
   638  func deleteBackendLocked(key BackendKey) error {
   639  	return key.Map().Delete(key)
   640  }
   641  
   642  func updateServiceEndpointV2(key ServiceKeyV2, value ServiceValueV2) error {
   643  	log.WithFields(logrus.Fields{
   644  		logfields.ServiceKey:   key,
   645  		logfields.ServiceValue: value,
   646  		logfields.SlaveSlot:    key.GetSlave(),
   647  	}).Debug("Upserting service entry")
   648  
   649  	if key.GetSlave() != 0 && value.RevNatKey().GetKey() == 0 {
   650  		return fmt.Errorf("invalid RevNat ID (0) in the Service Value")
   651  	}
   652  	if _, err := key.Map().OpenOrCreate(); err != nil {
   653  		return err
   654  	}
   655  
   656  	return key.Map().Update(key.ToNetwork(), value.ToNetwork())
   657  }
   658  
   659  // AddBackendIDsToCache populates the given backend IDs to the lbmap local cache.
   660  func AddBackendIDsToCache(backendIDs map[BackendAddrID]BackendKey) {
   661  	mutex.Lock()
   662  	defer mutex.Unlock()
   663  
   664  	cache.addBackendIDs(backendIDs)
   665  }
   666  
   667  // DeleteServiceV2 deletes a service from the lbmap and deletes backends of it if
   668  // they are not used by any other service.
   669  //
   670  //The given key has to be of the master service.
   671  func DeleteServiceV2(svc loadbalancer.L3n4AddrID, releaseBackendID func(loadbalancer.BackendID)) error {
   672  	mutex.Lock()
   673  	defer mutex.Unlock()
   674  
   675  	var (
   676  		svcKey ServiceKeyV2
   677  	)
   678  
   679  	isIPv6 := svc.IsIPv6()
   680  
   681  	log.WithField(logfields.ServiceName, svc).Debug("Deleting service")
   682  
   683  	if isIPv6 {
   684  		svcKey = NewService6KeyV2(svc.IP, svc.Port, u8proto.ANY, 0)
   685  	} else {
   686  		svcKey = NewService4KeyV2(svc.IP, svc.Port, u8proto.ANY, 0)
   687  	}
   688  
   689  	backendsToRemove, backendsCount, err := cache.removeServiceV2(svcKey)
   690  	if err != nil {
   691  		return err
   692  	}
   693  
   694  	for slot := 0; slot <= backendsCount; slot++ {
   695  		svcKey.SetSlave(slot)
   696  		if err := svcKey.MapDelete(); err != nil {
   697  			return err
   698  		}
   699  	}
   700  
   701  	for _, backendKey := range backendsToRemove {
   702  		if err := deleteBackendLocked(backendKey); err != nil {
   703  			return fmt.Errorf("Unable to delete backend with ID %d: %s", backendKey, err)
   704  		}
   705  		releaseBackendID(backendKey.GetID())
   706  		log.WithField(logfields.BackendID, backendKey).Debug("Deleted backend")
   707  	}
   708  
   709  	return nil
   710  }
   711  
   712  // DeleteServiceCache deletes the service cache.
   713  func DeleteServiceCache(svc loadbalancer.L3n4AddrID) {
   714  	mutex.Lock()
   715  	defer mutex.Unlock()
   716  
   717  	var svcKey ServiceKey
   718  
   719  	if !svc.IsIPv6() {
   720  		svcKey = NewService4Key(svc.IP, svc.Port, 0)
   721  	} else {
   722  		svcKey = NewService6Key(svc.IP, svc.Port, 0)
   723  	}
   724  
   725  	cache.delete(svcKey)
   726  }
   727  
   728  func DeleteOrphanBackends(releaseBackendID func(loadbalancer.BackendID)) []error {
   729  	mutex.Lock()
   730  	defer mutex.Unlock()
   731  
   732  	errors := make([]error, 0)
   733  	toRemove := cache.removeBackendsWithRefCountZero()
   734  
   735  	for _, key := range toRemove {
   736  		log.WithField(logfields.BackendID, key).Debug("Removing orphan backend")
   737  		if err := deleteBackendLocked(key); err != nil {
   738  			errors = append(errors,
   739  				fmt.Errorf("Unable to remove backend from the BPF map %d: %s", key, err))
   740  		}
   741  		releaseBackendID(key.GetID())
   742  	}
   743  
   744  	return errors
   745  }
   746  
   747  // RemoveDeprecatedMaps removes the maps for legacy services, left over from
   748  // previous installations.
   749  //
   750  // Safe to remove in Cilium 1.7.
   751  func RemoveDeprecatedMaps() error {
   752  	if err := Service6Map.UnpinIfExists(); err != nil {
   753  		return err
   754  	}
   755  	if err := RRSeq6Map.UnpinIfExists(); err != nil {
   756  		return err
   757  	}
   758  	if err := Service4Map.UnpinIfExists(); err != nil {
   759  		return err
   760  	}
   761  	if err := RRSeq4Map.UnpinIfExists(); err != nil {
   762  		return err
   763  	}
   764  	return nil
   765  }