Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b14d1dc
[gateway] Pass GatewayConfig to functions to simplify function calls.
npinaeva Jul 21, 2025
83601ec
[GatewayConfig] Rename gwLRPJoinIPs to gwRouterJoinNets
npinaeva Jul 21, 2025
bda9c47
[config] Rename TransitSwitchSUbnet to TransitSubnet
npinaeva Sep 4, 2025
9222a5f
[layer2-router] add logic to define current layer2 topology.
npinaeva Aug 20, 2025
2d0d07b
[tunnel-keys] Add tunnel keys allocator to cluster manager.
npinaeva Sep 9, 2025
1c2acdf
[layer2-router] Set and parse tunnel-keys for layer2 networks
npinaeva Sep 9, 2025
f772466
[layer2-router] Add gateway side
npinaeva Jul 31, 2025
a51c76e
[layer2-router] Add secondary_layer2_controller side
npinaeva Jul 31, 2025
c0e081f
[layer2-router] Services: put service routes on the transit router
npinaeva Jul 31, 2025
8523721
[layer2-router] add egressIP for new topology.
npinaeva Aug 1, 2025
18e0ddc
Upgrade: add cleanup and upgrade topology for local node.
npinaeva Aug 14, 2025
6aa7479
Upgrade: handle remote node upgrades to the new topology type.
npinaeva Aug 20, 2025
0922f65
Upgrade: add cleanup when all nodes are upgraded.
npinaeva Aug 14, 2025
9fb1cab
[podAnnotation] Use transit router port LLA for pod annotation
npinaeva Aug 18, 2025
69bb911
[e2e] BGP test: Layer2 UDN behaviour is not similar to Layer3.
npinaeva Aug 2, 2025
5344f07
[layer2-router] Update kubevirt tests to use default GW IP.
npinaeva Aug 22, 2025
3fa9798
[mockery] Update version to be compatible with go1.24
npinaeva Aug 25, 2025
7145cef
[layer2-router] set Layer2UsesTransitRouter to true for unit tests
npinaeva Aug 28, 2025
21c1e8b
[kind] Add ovnkube-identity to the deployed pods list
npinaeva Aug 28, 2025
77d3ebf
kv: Reconcile transit router as gateway after LM
npinaeva Sep 5, 2025
d42755b
kv: Add join subnet ipv6 pio with lifetime 0
npinaeva Sep 5, 2025
09602e1
Add transit subnet conflict handling for Layer2 networks.
npinaeva Sep 16, 2025
1eead4b
Add transit subnet conflict handling for Layer2 networks.
npinaeva Sep 16, 2025
5969bd7
kv: Add join subnet ipv6 pio with lifetime 0
npinaeva Sep 5, 2025
0a1d5d5
kv: Reconcile transit router as gateway after LM
npinaeva Sep 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions contrib/kind-helm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ set_default_params() {
export SVC_CIDR_IPV6=${SVC_CIDR_IPV6:-fd00:10:96::/112}
export JOIN_SUBNET_IPV4=${JOIN_SUBNET_IPV4:-100.64.0.0/16}
export JOIN_SUBNET_IPV6=${JOIN_SUBNET_IPV6:-fd98::/64}
export TRANSIT_SWITCH_SUBNET_IPV4=${TRANSIT_SWITCH_SUBNET_IPV4:-100.88.0.0/16}
export TRANSIT_SWITCH_SUBNET_IPV6=${TRANSIT_SWITCH_SUBNET_IPV6:-fd97::/64}
export TRANSIT_SUBNET_IPV4=${TRANSIT_SUBNET_IPV4:-100.88.0.0/16}
export TRANSIT_SUBNET_IPV6=${TRANSIT_SUBNET_IPV6:-fd97::/64}
export METALLB_CLIENT_NET_SUBNET_IPV4=${METALLB_CLIENT_NET_SUBNET_IPV4:-172.22.0.0/16}
export METALLB_CLIENT_NET_SUBNET_IPV6=${METALLB_CLIENT_NET_SUBNET_IPV6:-fc00:f853:ccd:e792::/64}

Expand Down
10 changes: 5 additions & 5 deletions contrib/kind.sh
Original file line number Diff line number Diff line change
Expand Up @@ -593,8 +593,8 @@ set_default_params() {
JOIN_SUBNET_IPV6=${JOIN_SUBNET_IPV6:-fd98::/64}
MASQUERADE_SUBNET_IPV4=${MASQUERADE_SUBNET_IPV4:-169.254.0.0/17}
MASQUERADE_SUBNET_IPV6=${MASQUERADE_SUBNET_IPV6:-fd69::/112}
TRANSIT_SWITCH_SUBNET_IPV4=${TRANSIT_SWITCH_SUBNET_IPV4:-100.88.0.0/16}
TRANSIT_SWITCH_SUBNET_IPV6=${TRANSIT_SWITCH_SUBNET_IPV6:-fd97::/64}
TRANSIT_SUBNET_IPV4=${TRANSIT_SUBNET_IPV4:-100.88.0.0/16}
TRANSIT_SUBNET_IPV6=${TRANSIT_SUBNET_IPV6:-fd97::/64}
METALLB_CLIENT_NET_SUBNET_IPV4=${METALLB_CLIENT_NET_SUBNET_IPV4:-172.22.0.0/16}
METALLB_CLIENT_NET_SUBNET_IPV6=${METALLB_CLIENT_NET_SUBNET_IPV6:-fc00:f853:ccd:e792::/64}
BGP_SERVER_NET_SUBNET_IPV4=${BGP_SERVER_NET_SUBNET_IPV4:-172.26.0.0/16}
Expand Down Expand Up @@ -631,7 +631,7 @@ set_default_params() {
OVN_HOST_NETWORK_NAMESPACE=${OVN_HOST_NETWORK_NAMESPACE:-ovn-host-network}
OVN_EGRESSIP_HEALTHCHECK_PORT=${OVN_EGRESSIP_HEALTHCHECK_PORT:-9107}
OCI_BIN=${KIND_EXPERIMENTAL_PROVIDER:-docker}
OVN_DEPLOY_PODS=${OVN_DEPLOY_PODS:-"ovnkube-zone-controller ovnkube-control-plane ovnkube-master ovnkube-node"}
OVN_DEPLOY_PODS=${OVN_DEPLOY_PODS:-"ovnkube-identity ovnkube-zone-controller ovnkube-control-plane ovnkube-master ovnkube-node"}
OVN_METRICS_SCALE_ENABLE=${OVN_METRICS_SCALE_ENABLE:-false}
OVN_ISOLATED=${OVN_ISOLATED:-false}
OVN_GATEWAY_OPTS=${OVN_GATEWAY_OPTS:-""}
Expand Down Expand Up @@ -914,8 +914,8 @@ create_ovn_kube_manifests() {
--v6-join-subnet="${JOIN_SUBNET_IPV6}" \
--v4-masquerade-subnet="${MASQUERADE_SUBNET_IPV4}" \
--v6-masquerade-subnet="${MASQUERADE_SUBNET_IPV6}" \
--v4-transit-switch-subnet="${TRANSIT_SWITCH_SUBNET_IPV4}" \
--v6-transit-switch-subnet="${TRANSIT_SWITCH_SUBNET_IPV6}" \
--v4-transit-subnet="${TRANSIT_SUBNET_IPV4}" \
--v6-transit-subnet="${TRANSIT_SUBNET_IPV6}" \
--ex-gw-network-interface="${OVN_EX_GW_NETWORK_INTERFACE}" \
--multi-network-enable="${ENABLE_MULTI_NET}" \
--network-segmentation-enable="${ENABLE_NETWORK_SEGMENTATION}" \
Expand Down
24 changes: 12 additions & 12 deletions dist/images/daemonset.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ OVN_V4_JOIN_SUBNET=""
OVN_V6_JOIN_SUBNET=""
OVN_V4_MASQUERADE_SUBNET=""
OVN_V6_MASQUERADE_SUBNET=""
OVN_V4_TRANSIT_SWITCH_SUBNET=""
OVN_V6_TRANSIT_SWITCH_SUBNET=""
OVN_V4_TRANSIT_SUBNET=""
OVN_V6_TRANSIT_SUBNET=""
OVN_NETFLOW_TARGETS=""
OVN_SFLOW_TARGETS=""
OVN_IPFIX_TARGETS=""
Expand Down Expand Up @@ -302,11 +302,11 @@ while [ "$1" != "" ]; do
--v6-masquerade-subnet)
OVN_V6_MASQUERADE_SUBNET=$VALUE
;;
--v4-transit-switch-subnet)
OVN_V4_TRANSIT_SWITCH_SUBNET=$VALUE
--v4-transit-subnet)
OVN_V4_TRANSIT_SUBNET=$VALUE
;;
--v6-transit-switch-subnet)
OVN_V6_TRANSIT_SWITCH_SUBNET=$VALUE
--v6-transit-subnet)
OVN_V6_TRANSIT_SUBNET=$VALUE
;;
--netflow-targets)
OVN_NETFLOW_TARGETS=$VALUE
Expand Down Expand Up @@ -536,10 +536,10 @@ ovn_v4_masquerade_subnet=${OVN_V4_MASQUERADE_SUBNET}
echo "ovn_v4_masquerade_subnet: ${ovn_v4_masquerade_subnet}"
ovn_v6_masquerade_subnet=${OVN_V6_MASQUERADE_SUBNET}
echo "ovn_v6_masquerade_subnet: ${ovn_v6_masquerade_subnet}"
ovn_v4_transit_switch_subnet=${OVN_V4_TRANSIT_SWITCH_SUBNET}
echo "ovn_v4_transit_switch_subnet: ${ovn_v4_transit_switch_subnet}"
ovn_v6_transit_switch_subnet=${OVN_V6_TRANSIT_SWITCH_SUBNET}
echo "ovn_v6_transit_switch_subnet: ${ovn_v6_transit_switch_subnet}"
ovn_v4_transit_subnet=${OVN_V4_TRANSIT_SUBNET}
echo "ovn_v4_transit_subnet: ${ovn_v4_transit_subnet}"
ovn_v6_transit_subnet=${OVN_V6_TRANSIT_SUBNET}
echo "ovn_v6_transit_subnet: ${ovn_v6_transit_subnet}"
ovn_netflow_targets=${OVN_NETFLOW_TARGETS}
echo "ovn_netflow_targets: ${ovn_netflow_targets}"
ovn_sflow_targets=${OVN_SFLOW_TARGETS}
Expand Down Expand Up @@ -842,8 +842,8 @@ ovn_image=${ovnkube_image} \
ovn_enable_multi_external_gateway=${ovn_enable_multi_external_gateway} \
ovn_enable_ovnkube_identity=${ovn_enable_ovnkube_identity} \
ovn_network_qos_enable=${ovn_network_qos_enable} \
ovn_v4_transit_switch_subnet=${ovn_v4_transit_switch_subnet} \
ovn_v6_transit_switch_subnet=${ovn_v6_transit_switch_subnet} \
ovn_v4_transit_subnet=${ovn_v4_transit_subnet} \
ovn_v6_transit_subnet=${ovn_v6_transit_subnet} \
ovn_enable_persistent_ips=${ovn_enable_persistent_ips} \
ovn_enable_dnsnameresolver=${ovn_enable_dnsnameresolver} \
ovn_observ_enable=${ovn_observ_enable} \
Expand Down
28 changes: 14 additions & 14 deletions dist/images/ovnkube.sh
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,10 @@ ovn_v6_join_subnet=${OVN_V6_JOIN_SUBNET:-}
ovn_v4_masquerade_subnet=${OVN_V4_MASQUERADE_SUBNET:-}
# OVN_V6_MASQUERADE_SUBNET - v6 masquerade subnet
ovn_v6_masquerade_subnet=${OVN_V6_MASQUERADE_SUBNET:-}
# OVN_V4_TRANSIT_SWITCH_SUBNET - v4 Transit switch subnet
ovn_v4_transit_switch_subnet=${OVN_V4_TRANSIT_SWITCH_SUBNET:-}
# OVN_V6_TRANSIT_SWITCH_SUBNET - v6 Transit switch subnet
ovn_v6_transit_switch_subnet=${OVN_V6_TRANSIT_SWITCH_SUBNET:-}
# OVN_V4_TRANSIT_SUBNET - v4 Transit subnet
ovn_v4_transit_subnet=${OVN_V4_TRANSIT_SUBNET:-}
# OVN_V6_TRANSIT_SUBNET - v6 Transit subnet
ovn_v6_transit_subnet=${OVN_V6_TRANSIT_SUBNET:-}
#OVN_REMOTE_PROBE_INTERVAL - ovn remote probe interval in ms (default 100000)
ovn_remote_probe_interval=${OVN_REMOTE_PROBE_INTERVAL:-100000}
#OVN_MONITOR_ALL - ovn-controller monitor all data in SB DB
Expand Down Expand Up @@ -2356,17 +2356,17 @@ ovn-cluster-manager() {
fi
echo "ovn_v6_masquerade_subnet_opt=${ovn_v6_masquerade_subnet_opt}"

ovn_v4_transit_switch_subnet_opt=
if [[ -n ${ovn_v4_transit_switch_subnet} ]]; then
ovn_v4_transit_switch_subnet_opt="--cluster-manager-v4-transit-switch-subnet=${ovn_v4_transit_switch_subnet}"
ovn_v4_transit_subnet_opt=
if [[ -n ${ovn_v4_transit_subnet} ]]; then
ovn_v4_transit_subnet_opt="--cluster-manager-v4-transit-subnet=${ovn_v4_transit_subnet}"
fi
echo "ovn_v4_transit_switch_subnet_opt=${ovn_v4_transit_switch_subnet}"
echo "ovn_v4_transit_subnet_opt=${ovn_v4_transit_subnet}"

ovn_v6_transit_switch_subnet_opt=
if [[ -n ${ovn_v6_transit_switch_subnet} ]]; then
ovn_v6_transit_switch_subnet_opt="--cluster-manager-v6-transit-switch-subnet=${ovn_v6_transit_switch_subnet}"
ovn_v6_transit_subnet_opt=
if [[ -n ${ovn_v6_transit_subnet} ]]; then
ovn_v6_transit_subnet_opt="--cluster-manager-v6-transit-subnet=${ovn_v6_transit_subnet}"
fi
echo "ovn_v6_transit_switch_subnet_opt=${ovn_v6_transit_switch_subnet}"
echo "ovn_v6_transit_subnet_opt=${ovn_v6_transit_subnet}"

multicast_enabled_flag=
if [[ ${ovn_multicast_enable} == "true" ]]; then
Expand Down Expand Up @@ -2476,8 +2476,8 @@ ovn-cluster-manager() {
${ovn_v4_masquerade_subnet_opt} \
${ovn_v6_join_subnet_opt} \
${ovn_v6_masquerade_subnet_opt} \
${ovn_v4_transit_switch_subnet_opt} \
${ovn_v6_transit_switch_subnet_opt} \
${ovn_v4_transit_subnet_opt} \
${ovn_v6_transit_subnet_opt} \
${network_qos_enabled_flag} \
${ovn_enable_dnsnameresolver_flag} \
--gateway-mode=${ovn_gateway_mode} \
Expand Down
8 changes: 4 additions & 4 deletions dist/templates/ovnkube-control-plane.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,10 @@ spec:
value: "{{ ovn_enable_interconnect }}"
- name: OVN_ENABLE_MULTI_EXTERNAL_GATEWAY
value: "{{ ovn_enable_multi_external_gateway }}"
- name: OVN_V4_TRANSIT_SWITCH_SUBNET
value: "{{ ovn_v4_transit_switch_subnet }}"
- name: OVN_V6_TRANSIT_SWITCH_SUBNET
value: "{{ ovn_v6_transit_switch_subnet }}"
- name: OVN_V4_TRANSIT_SUBNET
value: "{{ ovn_v4_transit_subnet }}"
- name: OVN_V6_TRANSIT_SUBNET
value: "{{ ovn_v6_transit_subnet }}"
- name: OVN_ENABLE_PERSISTENT_IPS
value: "{{ ovn_enable_persistent_ips }}"
- name: OVN_NETWORK_QOS_ENABLE
Expand Down
4 changes: 2 additions & 2 deletions docs/installation/ovnkube.1
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ Show help.
\fB\--version\fR, \fB\-v\fR
Print the version.
.TP
\fB\--cluster-manager-v4-transit-switch-subnet\fR string
\fB\--cluster-manager-v4-transit-subnet\fR string
The v4 transit switch subnet to use for assigning transit switch IPv4 addresses\fR.
.TP
\fB\--cluster-manager-v6-transit-switch-subnet\fR string
\fB\--cluster-manager-v6-transit-subnet\fR string
The v6 transit switch subnet to use for assigning transit switch IPv6 addresses\fR.

.SH "SEE ALSO"
Expand Down
5 changes: 2 additions & 3 deletions go-controller/.mockery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ packages:
github.com/ovn-org/ovn-kubernetes/go-controller/pkg/cni:
interfaces:
CNIPluginLibOps:
NetNS:
config:
dir: pkg/cni/mocks
github.com/ovn-org/ovn-kubernetes/go-controller/pkg/kube:
Expand All @@ -24,9 +23,9 @@ packages:
config:
all: true
dir: pkg/kube/mocks
github.com/ovn-org/ovn-kubernetes/go-controller/pkg/node:
github.com/ovn-org/ovn-kubernetes/go-controller/pkg/node/managementport:
interfaces:
ManagementPort:
Interface:
github.com/ovn-org/ovn-kubernetes/go-controller/pkg/ovn/address_set:
config:
all: true
Expand Down
2 changes: 1 addition & 1 deletion go-controller/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ TOOLS_OUTPUT_DIR = ${CURDIR}/${OUT_DIR}
MOCKERY = ${TOOLS_OUTPUT_DIR}/mockery-${MOCKERY_VERSION}

## Tool Versions
MOCKERY_VERSION ?= v2.43.2
MOCKERY_VERSION ?= v2.53.4

export NOROOT

Expand Down
127 changes: 120 additions & 7 deletions go-controller/pkg/allocator/id/allocator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package id

import (
"fmt"
"sync"
"slices"

bitmapallocator "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/allocator/bitmap"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/syncmap"
)

const (
Expand All @@ -28,7 +29,7 @@ type NamedAllocator interface {

// idAllocator is used to allocate id for a resource and store the resource - id in a map
type idAllocator struct {
nameIdMap sync.Map
nameIdMap *syncmap.SyncMap[int]
idBitmap *bitmapallocator.AllocationBitmap
}

Expand All @@ -37,18 +38,20 @@ func NewIDAllocator(name string, maxIds int) Allocator {
idBitmap := bitmapallocator.NewRoundRobinAllocationMap(maxIds, name)

return &idAllocator{
nameIdMap: sync.Map{},
nameIdMap: syncmap.NewSyncMap[int](),
idBitmap: idBitmap,
}
}

// AllocateID allocates an id for the resource 'name' and returns the id.
// If the id for the resource is already allocated, it returns the cached id.
func (idAllocator *idAllocator) AllocateID(name string) (int, error) {
idAllocator.nameIdMap.LockKey(name)
defer idAllocator.nameIdMap.UnlockKey(name)
// Check the idMap and return the id if its already allocated
v, ok := idAllocator.nameIdMap.Load(name)
if ok {
return v.(int), nil
return v, nil
}

id, allocated, _ := idAllocator.idBitmap.AllocateNext()
Expand All @@ -66,13 +69,15 @@ func (idAllocator *idAllocator) AllocateID(name string) (int, error) {
// It also returns an error if the resource 'name' has a different 'id'
// already reserved.
func (idAllocator *idAllocator) ReserveID(name string, id int) error {
idAllocator.nameIdMap.LockKey(name)
defer idAllocator.nameIdMap.UnlockKey(name)
v, ok := idAllocator.nameIdMap.Load(name)
if ok {
if v.(int) == id {
if v == id {
// All good. The id is already reserved by the same resource name.
return nil
}
return fmt.Errorf("can't reserve id %d for the resource %s. It is already allocated with a different id %d", id, name, v.(int))
return fmt.Errorf("can't reserve id %d for the resource %s. It is already allocated with a different id %d", id, name, v)
}

reserved, _ := idAllocator.idBitmap.Allocate(id)
Expand All @@ -86,9 +91,11 @@ func (idAllocator *idAllocator) ReserveID(name string, id int) error {

// ReleaseID releases the id allocated for the resource 'name'
func (idAllocator *idAllocator) ReleaseID(name string) {
idAllocator.nameIdMap.LockKey(name)
defer idAllocator.nameIdMap.UnlockKey(name)
v, ok := idAllocator.nameIdMap.Load(name)
if ok {
idAllocator.idBitmap.Release(v.(int))
idAllocator.idBitmap.Release(v)
idAllocator.nameIdMap.Delete(name)
}
}
Expand Down Expand Up @@ -116,3 +123,109 @@ func (allocator *namedAllocator) ReserveID(id int) error {
func (allocator *namedAllocator) ReleaseID() {
allocator.allocator.ReleaseID(allocator.name)
}

// idsAllocator is used to allocate multiple ids for a resource and store the resource - ids in a map
type idsAllocator struct {
// idBitmap allocated ids in range [0, maxIds-1]
idBitmap *bitmapallocator.AllocationBitmap
// offset can be used to shift the range to [offset, offset+maxIds-1]
offset int
// nameIdsMap stores the final allocated ids in range [offset, offset+maxIds-1] for a resource name
nameIdsMap *syncmap.SyncMap[[]int]
}

// newIDsAllocator returns an idsAllocator.
// If offset is non-zero, the allocated ids will be in the range [offset, offset+maxIds-1)
func newIDsAllocator(name string, maxIds int, offset int) *idsAllocator {
idBitmap := bitmapallocator.NewRoundRobinAllocationMap(maxIds, name)
return &idsAllocator{
nameIdsMap: syncmap.NewSyncMap[[]int](),
idBitmap: idBitmap,
offset: offset,
}
}

// AllocateIDs allocates numOfIDs for the resource 'name' and returns the ids.
// If less ids than numOfIDs are already allocated for the resource name, it will allocate the missing amount.
// If more ids than numOfIDs are already allocated for the resource name, it returns an error.
func (idsAllocator *idsAllocator) AllocateIDs(name string, numOfIDs int) ([]int, error) {
idsAllocator.nameIdsMap.LockKey(name)
defer idsAllocator.nameIdsMap.UnlockKey(name)
// Check the idMap and return the id if its already allocated
ids, ok := idsAllocator.nameIdsMap.Load(name)
if ok {
if len(ids) == numOfIDs {
return ids, nil
}
if len(ids) > numOfIDs {
return ids, fmt.Errorf("the resource %s already has more ids allocated %v than requested %v", name, ids, numOfIDs)
}
} else {
ids = make([]int, 0, numOfIDs)
}
previouslyAllocated := len(ids)
for len(ids) < numOfIDs {
id, allocated, _ := idsAllocator.idBitmap.AllocateNext()
if !allocated {
// release newly allocated ids
for _, id := range ids[previouslyAllocated:] {
idsAllocator.idBitmap.Release(id - idsAllocator.offset)
}
return ids, fmt.Errorf("failed to allocate the id for the resource %s", name)
}
ids = append(ids, id+idsAllocator.offset)
}
if len(ids) == 0 {
// don't store empty slice in the map
return ids, nil
}
idsAllocator.nameIdsMap.Store(name, ids)
return ids, nil
}

// ReserveIDs reserves 'ids' for the resource 'name'. It returns an
// error if one of the 'ids' is already reserved by a resource other than 'name'.
// It also returns an error if the resource 'name' has a different 'ids' slice
// already reserved. Slice elements order is important for comparison.
func (idsAllocator *idsAllocator) ReserveIDs(name string, ids []int) error {
idsAllocator.nameIdsMap.LockKey(name)
defer idsAllocator.nameIdsMap.UnlockKey(name)
existingIDs, ok := idsAllocator.nameIdsMap.Load(name)
if ok {
if slices.Equal(existingIDs, ids) {
// All good. The ids are already reserved by the same resource name.
return nil
}
return fmt.Errorf("can't reserve ids %v for the resource %s. It is already allocated with different ids %v",
ids, name, existingIDs)
}
allocatedIDs := make([]int, 0, len(ids))
for _, id := range ids {
// don't forget to adjust the id with the offset
reserved, _ := idsAllocator.idBitmap.Allocate(id - idsAllocator.offset)
if !reserved {
// cleanup previously allocated ids
for _, allocatedID := range allocatedIDs {
idsAllocator.idBitmap.Release(allocatedID - idsAllocator.offset)
}
return fmt.Errorf("id %d is already reserved by another resource", id)
}
allocatedIDs = append(allocatedIDs, id)
}
idsAllocator.nameIdsMap.Store(name, allocatedIDs)
return nil
}

// ReleaseIDs releases all ids allocated for the resource 'name'
func (idsAllocator *idsAllocator) ReleaseIDs(name string) {
idsAllocator.nameIdsMap.LockKey(name)
defer idsAllocator.nameIdsMap.UnlockKey(name)
existingIDs, ok := idsAllocator.nameIdsMap.Load(name)
if !ok {
return
}
for _, id := range existingIDs {
idsAllocator.idBitmap.Release(id - idsAllocator.offset)
}
idsAllocator.nameIdsMap.Delete(name)
}
Loading