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  }