github.phpd.cn/cilium/cilium@v1.6.12/pkg/service/id_local.go (about)

     1  // Copyright 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  	"fmt"
    19  
    20  	"github.com/cilium/cilium/pkg/loadbalancer"
    21  	"github.com/cilium/cilium/pkg/lock"
    22  )
    23  
    24  // IDAllocator contains an internal state of the ID allocator.
    25  type IDAllocator struct {
    26  	// Protects entitiesID, entities, nextID and maxID
    27  	lock.RWMutex
    28  
    29  	// entitiesID is a map of all entities indexed by service or backend ID
    30  	entitiesID map[uint32]*loadbalancer.L3n4AddrID
    31  
    32  	// entities is a map of all entities indexed by L3n4Addr.StringID()
    33  	entities map[string]uint32
    34  
    35  	// nextID is the next ID to attempt to allocate
    36  	nextID uint32
    37  
    38  	// maxID is the maximum ID available for allocation
    39  	maxID uint32
    40  
    41  	// initNextID is the initial nextID
    42  	initNextID uint32
    43  
    44  	// initMaxID is the initial maxID
    45  	initMaxID uint32
    46  }
    47  
    48  var (
    49  	serviceIDAlloc = NewIDAllocator(FirstFreeServiceID, MaxSetOfServiceID)
    50  	backendIDAlloc = NewIDAllocator(FirstFreeBackendID, MaxSetOfBackendID)
    51  )
    52  
    53  // NewIDAllocator creates a new ID allocator instance.
    54  func NewIDAllocator(nextID uint32, maxID uint32) *IDAllocator {
    55  	return &IDAllocator{
    56  		entitiesID: map[uint32]*loadbalancer.L3n4AddrID{},
    57  		entities:   map[string]uint32{},
    58  		nextID:     nextID,
    59  		maxID:      maxID,
    60  		initNextID: nextID,
    61  		initMaxID:  maxID,
    62  	}
    63  }
    64  
    65  func (alloc *IDAllocator) addID(svc loadbalancer.L3n4Addr, id uint32) *loadbalancer.L3n4AddrID {
    66  	svcID := newID(svc, id)
    67  	alloc.entitiesID[id] = svcID
    68  	alloc.entities[svc.StringID()] = id
    69  
    70  	return svcID
    71  }
    72  
    73  func (alloc *IDAllocator) acquireLocalID(svc loadbalancer.L3n4Addr, desiredID uint32) (*loadbalancer.L3n4AddrID, error) {
    74  	alloc.Lock()
    75  	defer alloc.Unlock()
    76  
    77  	if svcID, ok := alloc.entities[svc.StringID()]; ok {
    78  		if svc, ok := alloc.entitiesID[svcID]; ok {
    79  			return svc, nil
    80  		}
    81  	}
    82  
    83  	if desiredID != 0 {
    84  		if _, ok := alloc.entitiesID[desiredID]; !ok {
    85  			return alloc.addID(svc, desiredID), nil
    86  		}
    87  	}
    88  
    89  	startingID := alloc.nextID
    90  	rollover := false
    91  	for {
    92  		if alloc.nextID == startingID && rollover {
    93  			break
    94  		} else if alloc.nextID == alloc.maxID {
    95  			alloc.nextID = FirstFreeServiceID
    96  			rollover = true
    97  		}
    98  
    99  		if _, ok := alloc.entitiesID[alloc.nextID]; !ok {
   100  			svcID := alloc.addID(svc, alloc.nextID)
   101  			alloc.nextID++
   102  			return svcID, nil
   103  		}
   104  
   105  		alloc.nextID++
   106  	}
   107  
   108  	return nil, fmt.Errorf("no service ID available")
   109  }
   110  
   111  func (alloc *IDAllocator) getLocalID(id uint32) (*loadbalancer.L3n4AddrID, error) {
   112  	alloc.RLock()
   113  	defer alloc.RUnlock()
   114  
   115  	if svc, ok := alloc.entitiesID[id]; ok {
   116  		return svc, nil
   117  	}
   118  
   119  	return nil, nil
   120  }
   121  
   122  func (alloc *IDAllocator) deleteLocalID(id uint32) error {
   123  	alloc.Lock()
   124  	defer alloc.Unlock()
   125  
   126  	if svc, ok := alloc.entitiesID[id]; ok {
   127  		delete(alloc.entitiesID, id)
   128  		delete(alloc.entities, svc.StringID())
   129  	}
   130  
   131  	return nil
   132  }
   133  
   134  func (alloc *IDAllocator) lookupLocalID(svc loadbalancer.L3n4Addr) (uint32, error) {
   135  	alloc.RLock()
   136  	defer alloc.RUnlock()
   137  
   138  	if svcID, ok := alloc.entities[svc.StringID()]; ok {
   139  		return svcID, nil
   140  	}
   141  
   142  	return 0, fmt.Errorf("ID not found")
   143  }
   144  
   145  func (alloc *IDAllocator) setLocalIDSpace(next, max uint32) error {
   146  	alloc.Lock()
   147  	alloc.nextID = next
   148  	alloc.maxID = max
   149  	alloc.Unlock()
   150  
   151  	return nil
   152  }
   153  
   154  func (alloc *IDAllocator) getLocalMaxID() (uint32, error) {
   155  	alloc.RLock()
   156  	defer alloc.RUnlock()
   157  	return alloc.nextID, nil
   158  }
   159  
   160  func (alloc *IDAllocator) resetLocalID() {
   161  	alloc.Lock()
   162  	alloc.entitiesID = map[uint32]*loadbalancer.L3n4AddrID{}
   163  	alloc.entities = map[string]uint32{}
   164  	alloc.nextID = alloc.initNextID
   165  	alloc.maxID = alloc.initMaxID
   166  	alloc.Unlock()
   167  }
   168  
   169  func newID(svc loadbalancer.L3n4Addr, id uint32) *loadbalancer.L3n4AddrID {
   170  	return &loadbalancer.L3n4AddrID{
   171  		L3n4Addr: svc,
   172  		ID:       loadbalancer.ID(id),
   173  	}
   174  }