github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/ipam/allocator_test.go (about)

     1  package ipam
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"fmt"
     7  	"math/rand"
     8  	"net"
     9  	"net/netip"
    10  	"runtime"
    11  	"strconv"
    12  	"sync"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/bitmap"
    17  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/ipamapi"
    18  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/ipamutils"
    19  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/types"
    20  	"golang.org/x/sync/errgroup"
    21  	"gotest.tools/v3/assert"
    22  	is "gotest.tools/v3/assert/cmp"
    23  )
    24  
    25  func TestKeyString(t *testing.T) {
    26  	k := &PoolID{AddressSpace: "default", SubnetKey: SubnetKey{Subnet: netip.MustParsePrefix("172.27.0.0/16")}}
    27  	expected := "default/172.27.0.0/16"
    28  	if expected != k.String() {
    29  		t.Fatalf("Unexpected key string: %s", k.String())
    30  	}
    31  
    32  	k2, err := PoolIDFromString(expected)
    33  	if err != nil {
    34  		t.Fatal(err)
    35  	}
    36  	if k2.AddressSpace != k.AddressSpace || k2.Subnet != k.Subnet {
    37  		t.Fatalf("SubnetKey.FromString() failed. Expected %v. Got %v", k, k2)
    38  	}
    39  
    40  	expected = fmt.Sprintf("%s/%s", expected, "172.27.3.0/24")
    41  	k.ChildSubnet = netip.MustParsePrefix("172.27.3.0/24")
    42  	if expected != k.String() {
    43  		t.Fatalf("Unexpected key string: %s", k.String())
    44  	}
    45  
    46  	k2, err = PoolIDFromString(expected)
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  	if k2.AddressSpace != k.AddressSpace || k2.Subnet != k.Subnet || k2.ChildSubnet != k.ChildSubnet {
    51  		t.Fatalf("SubnetKey.FromString() failed. Expected %v. Got %v", k, k2)
    52  	}
    53  }
    54  
    55  func TestAddSubnets(t *testing.T) {
    56  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
    57  	if err != nil {
    58  		t.Fatal(err)
    59  	}
    60  
    61  	pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
    62  	if err != nil {
    63  		t.Fatal("Unexpected failure in adding subnet")
    64  	}
    65  
    66  	pid1, _, _, err := a.RequestPool(globalAddressSpace, "10.0.0.0/8", "", nil, false)
    67  	if err != nil {
    68  		t.Fatalf("Unexpected failure in adding overlapping subnets to different address spaces: %v", err)
    69  	}
    70  
    71  	if pid0 == pid1 {
    72  		t.Fatal("returned same pool id for same subnets in different namespaces")
    73  	}
    74  
    75  	_, _, _, err = a.RequestPool(globalAddressSpace, "10.0.0.0/8", "", nil, false)
    76  	if err == nil {
    77  		t.Fatalf("Expected failure requesting existing subnet")
    78  	}
    79  
    80  	_, _, _, err = a.RequestPool(globalAddressSpace, "10.128.0.0/9", "", nil, false)
    81  	if err == nil {
    82  		t.Fatal("Expected failure on adding overlapping base subnet")
    83  	}
    84  
    85  	_, _, _, err = a.RequestPool(globalAddressSpace, "10.0.0.0/8", "10.128.0.0/9", nil, false)
    86  	if err != nil {
    87  		t.Fatalf("Unexpected failure on adding sub pool: %v", err)
    88  	}
    89  	_, _, _, err = a.RequestPool(globalAddressSpace, "10.0.0.0/8", "10.128.0.0/9", nil, false)
    90  	if err == nil {
    91  		t.Fatalf("Expected failure on adding overlapping sub pool")
    92  	}
    93  
    94  	_, _, _, err = a.RequestPool(localAddressSpace, "10.20.2.0/24", "", nil, false)
    95  	if err == nil {
    96  		t.Fatal("Failed to detect overlapping subnets")
    97  	}
    98  
    99  	_, _, _, err = a.RequestPool(localAddressSpace, "10.128.0.0/9", "", nil, false)
   100  	if err == nil {
   101  		t.Fatal("Failed to detect overlapping subnets")
   102  	}
   103  
   104  	_, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3:4:5:6::/112", "", nil, false)
   105  	if err != nil {
   106  		t.Fatalf("Failed to add v6 subnet: %s", err.Error())
   107  	}
   108  
   109  	_, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3::/64", "", nil, false)
   110  	if err == nil {
   111  		t.Fatal("Failed to detect overlapping v6 subnet")
   112  	}
   113  }
   114  
   115  // TestDoublePoolRelease tests that releasing a pool which has already
   116  // been released raises an error.
   117  func TestDoublePoolRelease(t *testing.T) {
   118  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   119  	assert.NilError(t, err)
   120  
   121  	pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
   122  	assert.NilError(t, err)
   123  
   124  	err = a.ReleasePool(pid0)
   125  	assert.NilError(t, err)
   126  
   127  	err = a.ReleasePool(pid0)
   128  	assert.Check(t, is.ErrorContains(err, ""))
   129  }
   130  
   131  func TestAddReleasePoolID(t *testing.T) {
   132  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   133  	assert.NilError(t, err)
   134  
   135  	_, err = a.getAddrSpace(localAddressSpace)
   136  	if err != nil {
   137  		t.Fatal(err)
   138  	}
   139  
   140  	pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
   141  	if err != nil {
   142  		t.Fatalf("Unexpected failure in adding pool: %v", err)
   143  	}
   144  	k0, err := PoolIDFromString(pid0)
   145  	if err != nil {
   146  		t.Fatal(err)
   147  	}
   148  
   149  	aSpace, err := a.getAddrSpace(localAddressSpace)
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  
   154  	if got := aSpace.subnets[k0.Subnet].autoRelease; got != false {
   155  		t.Errorf("Unexpected autoRelease value for %s: %v", k0, got)
   156  	}
   157  
   158  	pid1, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false)
   159  	if err != nil {
   160  		t.Fatalf("Unexpected failure in adding sub pool: %v", err)
   161  	}
   162  	k1, err := PoolIDFromString(pid1)
   163  	if err != nil {
   164  		t.Fatal(err)
   165  	}
   166  
   167  	if pid0 == pid1 {
   168  		t.Fatalf("Incorrect poolIDs returned %s, %s", pid0, pid1)
   169  	}
   170  
   171  	aSpace, err = a.getAddrSpace(localAddressSpace)
   172  	if err != nil {
   173  		t.Fatal(err)
   174  	}
   175  
   176  	if got := aSpace.subnets[k1.Subnet].autoRelease; got != false {
   177  		t.Errorf("Unexpected autoRelease value for %s: %v", k1, got)
   178  	}
   179  
   180  	_, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false)
   181  	if err == nil {
   182  		t.Fatalf("Expected failure in adding sub pool: %v", err)
   183  	}
   184  
   185  	aSpace, err = a.getAddrSpace(localAddressSpace)
   186  	if err != nil {
   187  		t.Fatal(err)
   188  	}
   189  
   190  	if got := aSpace.subnets[k0.Subnet].autoRelease; got != false {
   191  		t.Errorf("Unexpected autoRelease value for %s: %v", k0, got)
   192  	}
   193  
   194  	if err := a.ReleasePool(pid1); err != nil {
   195  		t.Fatal(err)
   196  	}
   197  
   198  	aSpace, err = a.getAddrSpace(localAddressSpace)
   199  	if err != nil {
   200  		t.Fatal(err)
   201  	}
   202  
   203  	if got := aSpace.subnets[k0.Subnet].autoRelease; got != false {
   204  		t.Errorf("Unexpected autoRelease value for %s: %v", k0, got)
   205  	}
   206  	if err := a.ReleasePool(pid0); err != nil {
   207  		t.Error(err)
   208  	}
   209  
   210  	if _, ok := aSpace.subnets[k0.Subnet]; ok {
   211  		t.Error("Pool should have been deleted when released")
   212  	}
   213  
   214  	pid00, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
   215  	if err != nil {
   216  		t.Errorf("Unexpected failure in adding pool: %v", err)
   217  	}
   218  	if pid00 != pid0 {
   219  		t.Errorf("main pool should still exist. Got poolID %q, want %q", pid00, pid0)
   220  	}
   221  
   222  	aSpace, err = a.getAddrSpace(localAddressSpace)
   223  	if err != nil {
   224  		t.Fatal(err)
   225  	}
   226  
   227  	if got := aSpace.subnets[k0.Subnet].autoRelease; got != false {
   228  		t.Errorf("Unexpected autoRelease value for %s: %v", k0, got)
   229  	}
   230  
   231  	if err := a.ReleasePool(pid00); err != nil {
   232  		t.Error(err)
   233  	}
   234  
   235  	aSpace, err = a.getAddrSpace(localAddressSpace)
   236  	if err != nil {
   237  		t.Fatal(err)
   238  	}
   239  
   240  	if bp, ok := aSpace.subnets[k0.Subnet]; ok {
   241  		t.Errorf("Base pool %s is still present: %v", k0, bp)
   242  	}
   243  
   244  	_, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
   245  	if err != nil {
   246  		t.Errorf("Unexpected failure in adding pool: %v", err)
   247  	}
   248  
   249  	aSpace, err = a.getAddrSpace(localAddressSpace)
   250  	if err != nil {
   251  		t.Fatal(err)
   252  	}
   253  
   254  	if got := aSpace.subnets[k0.Subnet].autoRelease; got != false {
   255  		t.Errorf("Unexpected autoRelease value for %s: %v", k0, got)
   256  	}
   257  }
   258  
   259  func TestPredefinedPool(t *testing.T) {
   260  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   261  	assert.NilError(t, err)
   262  
   263  	pid, nw, _, err := a.RequestPool(localAddressSpace, "", "", nil, false)
   264  	if err != nil {
   265  		t.Fatal(err)
   266  	}
   267  
   268  	pid2, nw2, _, err := a.RequestPool(localAddressSpace, "", "", nil, false)
   269  	if err != nil {
   270  		t.Fatal(err)
   271  	}
   272  
   273  	if types.CompareIPNet(nw, nw2) {
   274  		t.Fatalf("Unexpected default network returned: %s = %s", nw2, nw)
   275  	}
   276  
   277  	if err := a.ReleasePool(pid); err != nil {
   278  		t.Fatal(err)
   279  	}
   280  
   281  	if err := a.ReleasePool(pid2); err != nil {
   282  		t.Fatal(err)
   283  	}
   284  }
   285  
   286  func TestRemoveSubnet(t *testing.T) {
   287  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   288  	assert.NilError(t, err)
   289  
   290  	input := []struct {
   291  		addrSpace string
   292  		subnet    string
   293  		v6        bool
   294  	}{
   295  		{localAddressSpace, "192.168.0.0/16", false},
   296  		{localAddressSpace, "172.17.0.0/16", false},
   297  		{localAddressSpace, "10.0.0.0/8", false},
   298  		{localAddressSpace, "2001:db8:1:2:3:4:ffff::/112", false},
   299  		{globalAddressSpace, "172.17.0.0/16", false},
   300  		{globalAddressSpace, "10.0.0.0/8", false},
   301  		{globalAddressSpace, "2001:db8:1:2:3:4:5::/112", true},
   302  		{globalAddressSpace, "2001:db8:1:2:3:4:ffff::/112", true},
   303  	}
   304  
   305  	poolIDs := make([]string, len(input))
   306  
   307  	for ind, i := range input {
   308  		if poolIDs[ind], _, _, err = a.RequestPool(i.addrSpace, i.subnet, "", nil, i.v6); err != nil {
   309  			t.Fatalf("Failed to apply input. Can't proceed: %s", err.Error())
   310  		}
   311  	}
   312  
   313  	for ind, id := range poolIDs {
   314  		if err := a.ReleasePool(id); err != nil {
   315  			t.Fatalf("Failed to release poolID %s (%d)", id, ind)
   316  		}
   317  	}
   318  }
   319  
   320  func TestGetSameAddress(t *testing.T) {
   321  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   322  	assert.NilError(t, err)
   323  
   324  	pid, _, _, err := a.RequestPool(localAddressSpace, "192.168.100.0/24", "", nil, false)
   325  	if err != nil {
   326  		t.Fatal(err)
   327  	}
   328  
   329  	ip := net.ParseIP("192.168.100.250")
   330  	_, _, err = a.RequestAddress(pid, ip, nil)
   331  	if err != nil {
   332  		t.Fatal(err)
   333  	}
   334  
   335  	_, _, err = a.RequestAddress(pid, ip, nil)
   336  	if err == nil {
   337  		t.Fatal(err)
   338  	}
   339  }
   340  
   341  func TestPoolAllocationReuse(t *testing.T) {
   342  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   343  	assert.NilError(t, err)
   344  
   345  	// First get all pools until they are exhausted to
   346  	pList := []string{}
   347  	pool, _, _, err := a.RequestPool(localAddressSpace, "", "", nil, false)
   348  	for err == nil {
   349  		pList = append(pList, pool)
   350  		pool, _, _, err = a.RequestPool(localAddressSpace, "", "", nil, false)
   351  	}
   352  	nPools := len(pList)
   353  	for _, pool := range pList {
   354  		if err := a.ReleasePool(pool); err != nil {
   355  			t.Fatal(err)
   356  		}
   357  	}
   358  
   359  	// Now try to allocate then free nPool pools sequentially.
   360  	// Verify that we don't see any repeat networks even though
   361  	// we have freed them.
   362  	seen := map[string]bool{}
   363  	for i := 0; i < nPools; i++ {
   364  		pool, nw, _, err := a.RequestPool(localAddressSpace, "", "", nil, false)
   365  		if err != nil {
   366  			t.Fatal(err)
   367  		}
   368  		if _, ok := seen[nw.String()]; ok {
   369  			t.Fatalf("Network %s was reused before exhausing the pool list", nw.String())
   370  		}
   371  		seen[nw.String()] = true
   372  		if err := a.ReleasePool(pool); err != nil {
   373  			t.Fatal(err)
   374  		}
   375  	}
   376  }
   377  
   378  func TestGetAddressSubPoolEqualPool(t *testing.T) {
   379  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   380  	assert.NilError(t, err)
   381  
   382  	// Requesting a subpool of same size of the master pool should not cause any problem on ip allocation
   383  	pid, _, _, err := a.RequestPool(localAddressSpace, "172.18.0.0/16", "172.18.0.0/16", nil, false)
   384  	if err != nil {
   385  		t.Fatal(err)
   386  	}
   387  
   388  	_, _, err = a.RequestAddress(pid, nil, nil)
   389  	if err != nil {
   390  		t.Fatal(err)
   391  	}
   392  }
   393  
   394  func TestRequestReleaseAddressFromSubPool(t *testing.T) {
   395  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   396  	assert.NilError(t, err)
   397  
   398  	poolID, _, _, err := a.RequestPool(localAddressSpace, "172.28.0.0/16", "172.28.30.0/24", nil, false)
   399  	if err != nil {
   400  		t.Fatal(err)
   401  	}
   402  
   403  	var ip *net.IPNet
   404  	expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}}
   405  	for err == nil {
   406  		var c *net.IPNet
   407  		if c, _, err = a.RequestAddress(poolID, nil, nil); err == nil {
   408  			ip = c
   409  		}
   410  	}
   411  	if err != ipamapi.ErrNoAvailableIPs {
   412  		t.Fatal(err)
   413  	}
   414  	if !types.CompareIPNet(expected, ip) {
   415  		t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
   416  	}
   417  	rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}}
   418  	if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
   419  		t.Fatal(err)
   420  	}
   421  	if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil {
   422  		t.Fatal(err)
   423  	}
   424  	if !types.CompareIPNet(rp, ip) {
   425  		t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
   426  	}
   427  
   428  	_, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false)
   429  	if err != nil {
   430  		t.Fatal(err)
   431  	}
   432  	poolID, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/16", "10.0.0.0/24", nil, false)
   433  	if err != nil {
   434  		t.Fatal(err)
   435  	}
   436  	expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}}
   437  	for err == nil {
   438  		var c *net.IPNet
   439  		if c, _, err = a.RequestAddress(poolID, nil, nil); err == nil {
   440  			ip = c
   441  		}
   442  	}
   443  	if err != ipamapi.ErrNoAvailableIPs {
   444  		t.Fatal(err)
   445  	}
   446  	if !types.CompareIPNet(expected, ip) {
   447  		t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
   448  	}
   449  	rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}}
   450  	if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
   451  		t.Fatal(err)
   452  	}
   453  	if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil {
   454  		t.Fatal(err)
   455  	}
   456  	if !types.CompareIPNet(rp, ip) {
   457  		t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
   458  	}
   459  
   460  	// Request any addresses from subpool after explicit address request
   461  	unoExp, _ := types.ParseCIDR("10.2.2.0/16")
   462  	dueExp, _ := types.ParseCIDR("10.2.2.2/16")
   463  	treExp, _ := types.ParseCIDR("10.2.2.1/16")
   464  
   465  	if poolID, _, _, err = a.RequestPool(localAddressSpace, "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil {
   466  		t.Fatal(err)
   467  	}
   468  	tre, _, err := a.RequestAddress(poolID, treExp.IP, nil)
   469  	if err != nil {
   470  		t.Fatal(err)
   471  	}
   472  	if !types.CompareIPNet(tre, treExp) {
   473  		t.Fatalf("Unexpected address: want %v, got %v", treExp, tre)
   474  	}
   475  
   476  	uno, _, err := a.RequestAddress(poolID, nil, nil)
   477  	if err != nil {
   478  		t.Fatal(err)
   479  	}
   480  	if !types.CompareIPNet(uno, unoExp) {
   481  		t.Fatalf("Unexpected address: %v", uno)
   482  	}
   483  
   484  	due, _, err := a.RequestAddress(poolID, nil, nil)
   485  	if err != nil {
   486  		t.Fatal(err)
   487  	}
   488  	if !types.CompareIPNet(due, dueExp) {
   489  		t.Fatalf("Unexpected address: %v", due)
   490  	}
   491  
   492  	if err = a.ReleaseAddress(poolID, uno.IP); err != nil {
   493  		t.Fatal(err)
   494  	}
   495  	uno, _, err = a.RequestAddress(poolID, nil, nil)
   496  	if err != nil {
   497  		t.Fatal(err)
   498  	}
   499  	if !types.CompareIPNet(uno, unoExp) {
   500  		t.Fatalf("Unexpected address: %v", uno)
   501  	}
   502  
   503  	if err = a.ReleaseAddress(poolID, tre.IP); err != nil {
   504  		t.Fatal(err)
   505  	}
   506  	tre, _, err = a.RequestAddress(poolID, nil, nil)
   507  	if err != nil {
   508  		t.Fatal(err)
   509  	}
   510  	if !types.CompareIPNet(tre, treExp) {
   511  		t.Fatalf("Unexpected address: %v", tre)
   512  	}
   513  }
   514  
   515  func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
   516  	opts := map[string]string{
   517  		ipamapi.AllocSerialPrefix: "true",
   518  	}
   519  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   520  	assert.NilError(t, err)
   521  
   522  	poolID, _, _, err := a.RequestPool(localAddressSpace, "172.28.0.0/16", "172.28.30.0/24", nil, false)
   523  	if err != nil {
   524  		t.Fatal(err)
   525  	}
   526  
   527  	var ip *net.IPNet
   528  	expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}}
   529  	for err == nil {
   530  		var c *net.IPNet
   531  		if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil {
   532  			ip = c
   533  		}
   534  	}
   535  	if err != ipamapi.ErrNoAvailableIPs {
   536  		t.Fatal(err)
   537  	}
   538  	if !types.CompareIPNet(expected, ip) {
   539  		t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
   540  	}
   541  	rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}}
   542  	if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
   543  		t.Fatal(err)
   544  	}
   545  	if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil {
   546  		t.Fatal(err)
   547  	}
   548  	if !types.CompareIPNet(rp, ip) {
   549  		t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
   550  	}
   551  
   552  	_, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false)
   553  	if err != nil {
   554  		t.Fatal(err)
   555  	}
   556  	poolID, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/16", "10.0.0.0/24", nil, false)
   557  	if err != nil {
   558  		t.Fatal(err)
   559  	}
   560  	expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}}
   561  	for err == nil {
   562  		var c *net.IPNet
   563  		if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil {
   564  			ip = c
   565  		}
   566  	}
   567  	if err != ipamapi.ErrNoAvailableIPs {
   568  		t.Fatal(err)
   569  	}
   570  	if !types.CompareIPNet(expected, ip) {
   571  		t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
   572  	}
   573  	rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}}
   574  	if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
   575  		t.Fatal(err)
   576  	}
   577  	if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil {
   578  		t.Fatal(err)
   579  	}
   580  	if !types.CompareIPNet(rp, ip) {
   581  		t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
   582  	}
   583  
   584  	// Request any addresses from subpool after explicit address request
   585  	unoExp, _ := types.ParseCIDR("10.2.2.0/16")
   586  	dueExp, _ := types.ParseCIDR("10.2.2.2/16")
   587  	treExp, _ := types.ParseCIDR("10.2.2.1/16")
   588  	quaExp, _ := types.ParseCIDR("10.2.2.3/16")
   589  	fivExp, _ := types.ParseCIDR("10.2.2.4/16")
   590  	if poolID, _, _, err = a.RequestPool(localAddressSpace, "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil {
   591  		t.Fatal(err)
   592  	}
   593  	tre, _, err := a.RequestAddress(poolID, treExp.IP, opts)
   594  	if err != nil {
   595  		t.Fatal(err)
   596  	}
   597  	if !types.CompareIPNet(tre, treExp) {
   598  		t.Fatalf("Unexpected address: want %v, got %v", treExp, tre)
   599  	}
   600  
   601  	uno, _, err := a.RequestAddress(poolID, nil, opts)
   602  	if err != nil {
   603  		t.Fatal(err)
   604  	}
   605  	if !types.CompareIPNet(uno, unoExp) {
   606  		t.Fatalf("Unexpected address: %v", uno)
   607  	}
   608  
   609  	due, _, err := a.RequestAddress(poolID, nil, opts)
   610  	if err != nil {
   611  		t.Fatal(err)
   612  	}
   613  	if !types.CompareIPNet(due, dueExp) {
   614  		t.Fatalf("Unexpected address: %v", due)
   615  	}
   616  
   617  	if err = a.ReleaseAddress(poolID, uno.IP); err != nil {
   618  		t.Fatal(err)
   619  	}
   620  	uno, _, err = a.RequestAddress(poolID, nil, opts)
   621  	if err != nil {
   622  		t.Fatal(err)
   623  	}
   624  	if !types.CompareIPNet(uno, quaExp) {
   625  		t.Fatalf("Unexpected address: %v", uno)
   626  	}
   627  
   628  	if err = a.ReleaseAddress(poolID, tre.IP); err != nil {
   629  		t.Fatal(err)
   630  	}
   631  	tre, _, err = a.RequestAddress(poolID, nil, opts)
   632  	if err != nil {
   633  		t.Fatal(err)
   634  	}
   635  	if !types.CompareIPNet(tre, fivExp) {
   636  		t.Fatalf("Unexpected address: %v", tre)
   637  	}
   638  }
   639  
   640  func TestGetAddress(t *testing.T) {
   641  	input := []string{
   642  		/*"10.0.0.0/8", "10.0.0.0/9", "10.0.0.0/10",*/ "10.0.0.0/11", "10.0.0.0/12", "10.0.0.0/13", "10.0.0.0/14",
   643  		"10.0.0.0/15", "10.0.0.0/16", "10.0.0.0/17", "10.0.0.0/18", "10.0.0.0/19", "10.0.0.0/20", "10.0.0.0/21",
   644  		"10.0.0.0/22", "10.0.0.0/23", "10.0.0.0/24", "10.0.0.0/25", "10.0.0.0/26", "10.0.0.0/27", "10.0.0.0/28",
   645  		"10.0.0.0/29", "10.0.0.0/30", "10.0.0.0/31",
   646  	}
   647  
   648  	for _, subnet := range input {
   649  		assertGetAddress(t, subnet)
   650  	}
   651  }
   652  
   653  func TestRequestSyntaxCheck(t *testing.T) {
   654  	var (
   655  		pool    = "192.168.0.0/16"
   656  		subPool = "192.168.0.0/24"
   657  	)
   658  
   659  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   660  	assert.NilError(t, err)
   661  
   662  	_, _, _, err = a.RequestPool("", pool, "", nil, false)
   663  	if err == nil {
   664  		t.Fatal("Failed to detect wrong request: empty address space")
   665  	}
   666  
   667  	_, _, _, err = a.RequestPool("", pool, subPool, nil, false)
   668  	if err == nil {
   669  		t.Fatal("Failed to detect wrong request: empty address space")
   670  	}
   671  
   672  	_, _, _, err = a.RequestPool(localAddressSpace, "", subPool, nil, false)
   673  	if err == nil {
   674  		t.Fatal("Failed to detect wrong request: subPool specified and no pool")
   675  	}
   676  
   677  	pid, _, _, err := a.RequestPool(localAddressSpace, pool, subPool, nil, false)
   678  	if err != nil {
   679  		t.Fatalf("Unexpected failure: %v", err)
   680  	}
   681  
   682  	_, _, err = a.RequestAddress("", nil, nil)
   683  	if err == nil {
   684  		t.Fatal("Failed to detect wrong request: no pool id specified")
   685  	}
   686  
   687  	ip := net.ParseIP("172.17.0.23")
   688  	_, _, err = a.RequestAddress(pid, ip, nil)
   689  	if err == nil {
   690  		t.Fatal("Failed to detect wrong request: requested IP from different subnet")
   691  	}
   692  
   693  	ip = net.ParseIP("192.168.0.50")
   694  	_, _, err = a.RequestAddress(pid, ip, nil)
   695  	if err != nil {
   696  		t.Fatalf("Unexpected failure: %v", err)
   697  	}
   698  
   699  	err = a.ReleaseAddress("", ip)
   700  	if err == nil {
   701  		t.Fatal("Failed to detect wrong request: no pool id specified")
   702  	}
   703  
   704  	err = a.ReleaseAddress(pid, nil)
   705  	if err == nil {
   706  		t.Fatal("Failed to detect wrong request: no pool id specified")
   707  	}
   708  
   709  	err = a.ReleaseAddress(pid, ip)
   710  	if err != nil {
   711  		t.Fatalf("Unexpected failure: %v: %s, %s", err, pid, ip)
   712  	}
   713  }
   714  
   715  func TestRequest(t *testing.T) {
   716  	// Request N addresses from different size subnets, verifying last request
   717  	// returns expected address. Internal subnet host size is Allocator's default, 16
   718  	input := []struct {
   719  		subnet string
   720  		numReq int
   721  		lastIP string
   722  	}{
   723  		{"192.168.59.0/24", 254, "192.168.59.254"},
   724  		{"192.168.240.0/20", 255, "192.168.240.255"},
   725  		{"192.168.0.0/16", 255, "192.168.0.255"},
   726  		{"192.168.0.0/16", 256, "192.168.1.0"},
   727  		{"10.16.0.0/16", 255, "10.16.0.255"},
   728  		{"10.128.0.0/12", 255, "10.128.0.255"},
   729  		{"10.0.0.0/8", 256, "10.0.1.0"},
   730  
   731  		{"192.168.128.0/18", 4*256 - 1, "192.168.131.255"},
   732  		/*
   733  			{"192.168.240.0/20", 16*256 - 2, "192.168.255.254"},
   734  
   735  			{"192.168.0.0/16", 256*256 - 2, "192.168.255.254"},
   736  			{"10.0.0.0/8", 2 * 256, "10.0.2.0"},
   737  			{"10.0.0.0/8", 5 * 256, "10.0.5.0"},
   738  			{"10.0.0.0/8", 100 * 256 * 254, "10.99.255.254"},
   739  		*/
   740  	}
   741  
   742  	for _, d := range input {
   743  		assertNRequests(t, d.subnet, d.numReq, d.lastIP)
   744  	}
   745  }
   746  
   747  // TestOverlappingRequests tests that overlapping subnets cannot be allocated.
   748  // Requests for subnets which are supersets or subsets of existing allocations,
   749  // or which overlap at the beginning or end, should not be permitted.
   750  func TestOverlappingRequests(t *testing.T) {
   751  	input := []struct {
   752  		environment []string
   753  		subnet      string
   754  		ok          bool
   755  	}{
   756  		// IPv4
   757  		// Previously allocated network does not overlap with request
   758  		{[]string{"10.0.0.0/8"}, "11.0.0.0/8", true},
   759  		{[]string{"74.0.0.0/7"}, "9.111.99.72/30", true},
   760  		{[]string{"110.192.0.0/10"}, "16.0.0.0/10", true},
   761  
   762  		// Previously allocated network entirely contains request
   763  		{[]string{"10.0.0.0/8"}, "10.0.0.0/8", false}, // exact overlap
   764  		{[]string{"0.0.0.0/1"}, "16.182.0.0/15", false},
   765  		{[]string{"16.0.0.0/4"}, "17.11.66.0/23", false},
   766  
   767  		// Previously allocated network overlaps beginning of request
   768  		{[]string{"0.0.0.0/1"}, "0.0.0.0/0", false},
   769  		{[]string{"64.0.0.0/6"}, "64.0.0.0/3", false},
   770  		{[]string{"112.0.0.0/6"}, "112.0.0.0/4", false},
   771  
   772  		// Previously allocated network overlaps end of request
   773  		{[]string{"96.0.0.0/3"}, "0.0.0.0/1", false},
   774  		{[]string{"192.0.0.0/2"}, "128.0.0.0/1", false},
   775  		{[]string{"95.0.0.0/8"}, "92.0.0.0/6", false},
   776  
   777  		// Previously allocated network entirely contained within request
   778  		{[]string{"10.0.0.0/8"}, "10.0.0.0/6", false}, // non-canonical
   779  		{[]string{"10.0.0.0/8"}, "8.0.0.0/6", false},  // canonical
   780  		{[]string{"25.173.144.0/20"}, "0.0.0.0/0", false},
   781  
   782  		// IPv6
   783  		// Previously allocated network entirely contains request
   784  		{[]string{"::/0"}, "f656:3484:c878:a05:e540:a6ed:4d70:3740/123", false},
   785  		{[]string{"8000::/1"}, "8fe8:e7c4:5779::/49", false},
   786  		{[]string{"f000::/4"}, "ffc7:6000::/19", false},
   787  
   788  		// Previously allocated network overlaps beginning of request
   789  		{[]string{"::/2"}, "::/0", false},
   790  		{[]string{"::/3"}, "::/1", false},
   791  		{[]string{"::/6"}, "::/5", false},
   792  
   793  		// Previously allocated network overlaps end of request
   794  		{[]string{"c000::/2"}, "8000::/1", false},
   795  		{[]string{"7c00::/6"}, "::/1", false},
   796  		{[]string{"cf80::/9"}, "c000::/4", false},
   797  
   798  		// Previously allocated network entirely contained within request
   799  		{[]string{"ff77:93f8::/29"}, "::/0", false},
   800  		{[]string{"9287:2e20:5134:fab6:9061:a0c6:bfe3:9400/119"}, "8000::/1", false},
   801  		{[]string{"3ea1:bfa9:8691:d1c6:8c46:519b:db6d:e700/120"}, "3000::/4", false},
   802  	}
   803  
   804  	for _, tc := range input {
   805  		a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   806  		assert.NilError(t, err)
   807  
   808  		// Set up some existing allocations.  This should always succeed.
   809  		for _, env := range tc.environment {
   810  			_, _, _, err = a.RequestPool(localAddressSpace, env, "", nil, false)
   811  			assert.NilError(t, err)
   812  		}
   813  
   814  		// Make the test allocation.
   815  		_, _, _, err = a.RequestPool(localAddressSpace, tc.subnet, "", nil, false)
   816  		if tc.ok {
   817  			assert.NilError(t, err)
   818  		} else {
   819  			assert.Check(t, is.ErrorContains(err, ""))
   820  		}
   821  	}
   822  }
   823  
   824  func TestUnusualSubnets(t *testing.T) {
   825  	subnet := "192.168.0.2/31"
   826  
   827  	outsideTheRangeAddresses := []struct {
   828  		address string
   829  	}{
   830  		{"192.168.0.1"},
   831  		{"192.168.0.4"},
   832  		{"192.168.0.100"},
   833  	}
   834  
   835  	expectedAddresses := []struct {
   836  		address string
   837  	}{
   838  		{"192.168.0.2"},
   839  		{"192.168.0.3"},
   840  	}
   841  
   842  	allocator, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   843  	if err != nil {
   844  		t.Fatal(err)
   845  	}
   846  
   847  	//
   848  	// IPv4 /31 blocks.  See RFC 3021.
   849  	//
   850  
   851  	pool, _, _, err := allocator.RequestPool(localAddressSpace, subnet, "", nil, false)
   852  	if err != nil {
   853  		t.Fatal(err)
   854  	}
   855  
   856  	// Outside-the-range
   857  
   858  	for _, outside := range outsideTheRangeAddresses {
   859  		_, _, errx := allocator.RequestAddress(pool, net.ParseIP(outside.address), nil)
   860  		if errx != ipamapi.ErrIPOutOfRange {
   861  			t.Fatalf("Address %s failed to throw expected error: %s", outside.address, errx.Error())
   862  		}
   863  	}
   864  
   865  	// Should get just these two IPs followed by exhaustion on the next request
   866  
   867  	for _, expected := range expectedAddresses {
   868  		got, _, errx := allocator.RequestAddress(pool, nil, nil)
   869  		if errx != nil {
   870  			t.Fatalf("Failed to obtain the address: %s", errx.Error())
   871  		}
   872  		expectedIP := net.ParseIP(expected.address)
   873  		gotIP := got.IP
   874  		if !gotIP.Equal(expectedIP) {
   875  			t.Fatalf("Failed to obtain sequentialaddress. Expected: %s, Got: %s", expectedIP, gotIP)
   876  		}
   877  	}
   878  
   879  	_, _, err = allocator.RequestAddress(pool, nil, nil)
   880  	if err != ipamapi.ErrNoAvailableIPs {
   881  		t.Fatal("Did not get expected error when pool is exhausted.")
   882  	}
   883  }
   884  
   885  func TestRelease(t *testing.T) {
   886  	subnet := "192.168.0.0/23"
   887  
   888  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   889  	assert.NilError(t, err)
   890  
   891  	pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false)
   892  	if err != nil {
   893  		t.Fatal(err)
   894  	}
   895  
   896  	// Allocate all addresses
   897  	for err != ipamapi.ErrNoAvailableIPs {
   898  		_, _, err = a.RequestAddress(pid, nil, nil)
   899  	}
   900  
   901  	toRelease := []struct {
   902  		address string
   903  	}{
   904  		{"192.168.0.1"},
   905  		{"192.168.0.2"},
   906  		{"192.168.0.3"},
   907  		{"192.168.0.4"},
   908  		{"192.168.0.5"},
   909  		{"192.168.0.6"},
   910  		{"192.168.0.7"},
   911  		{"192.168.0.8"},
   912  		{"192.168.0.9"},
   913  		{"192.168.0.10"},
   914  		{"192.168.0.30"},
   915  		{"192.168.0.31"},
   916  		{"192.168.1.32"},
   917  
   918  		{"192.168.0.254"},
   919  		{"192.168.1.1"},
   920  		{"192.168.1.2"},
   921  
   922  		{"192.168.1.3"},
   923  
   924  		{"192.168.1.253"},
   925  		{"192.168.1.254"},
   926  	}
   927  
   928  	// One by one, release the address and request again. We should get the same IP
   929  	for i, inp := range toRelease {
   930  		ip0 := net.ParseIP(inp.address)
   931  		a.ReleaseAddress(pid, ip0)
   932  		bm := a.local.subnets[netip.MustParsePrefix(subnet)].addrs
   933  		if bm.Unselected() != 1 {
   934  			t.Fatalf("Failed to update free address count after release. Expected %d, Found: %d", i+1, bm.Unselected())
   935  		}
   936  
   937  		nw, _, err := a.RequestAddress(pid, nil, nil)
   938  		if err != nil {
   939  			t.Fatalf("Failed to obtain the address: %s", err.Error())
   940  		}
   941  		ip := nw.IP
   942  		if !ip0.Equal(ip) {
   943  			t.Fatalf("Failed to obtain the same address. Expected: %s, Got: %s", ip0, ip)
   944  		}
   945  	}
   946  }
   947  
   948  func assertGetAddress(t *testing.T, subnet string) {
   949  	var (
   950  		err       error
   951  		printTime = false
   952  	)
   953  
   954  	sub := netip.MustParsePrefix(subnet)
   955  	ones, bits := sub.Bits(), sub.Addr().BitLen()
   956  	zeroes := bits - ones
   957  	numAddresses := 1 << uint(zeroes)
   958  
   959  	bm := bitmap.New(uint64(numAddresses))
   960  
   961  	start := time.Now()
   962  	run := 0
   963  	for err != ipamapi.ErrNoAvailableIPs {
   964  		_, err = getAddress(sub, bm, netip.Addr{}, netip.Prefix{}, false)
   965  		run++
   966  	}
   967  	if printTime {
   968  		fmt.Printf("\nTaken %v, to allocate all addresses on %s. (nemAddresses: %d. Runs: %d)", time.Since(start), subnet, numAddresses, run)
   969  	}
   970  	if bm.Unselected() != 0 {
   971  		t.Fatalf("Unexpected free count after reserving all addresses: %d", bm.Unselected())
   972  	}
   973  	/*
   974  		if bm.Head.Block != expectedMax || bm.Head.Count != numBlocks {
   975  			t.Fatalf("Failed to effectively reserve all addresses on %s. Expected (0x%x, %d) as first sequence. Found (0x%x,%d)",
   976  				subnet, expectedMax, numBlocks, bm.Head.Block, bm.Head.Count)
   977  		}
   978  	*/
   979  }
   980  
   981  func assertNRequests(t *testing.T, subnet string, numReq int, lastExpectedIP string) {
   982  	var (
   983  		nw        *net.IPNet
   984  		printTime = false
   985  	)
   986  
   987  	lastIP := net.ParseIP(lastExpectedIP)
   988  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
   989  	assert.NilError(t, err)
   990  
   991  	pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false)
   992  	if err != nil {
   993  		t.Fatal(err)
   994  	}
   995  
   996  	i := 0
   997  	start := time.Now()
   998  	for ; i < numReq; i++ {
   999  		nw, _, err = a.RequestAddress(pid, nil, nil)
  1000  		if err != nil {
  1001  			t.Fatal(err)
  1002  		}
  1003  	}
  1004  	if printTime {
  1005  		fmt.Printf("\nTaken %v, to allocate %d addresses on %s\n", time.Since(start), numReq, subnet)
  1006  	}
  1007  
  1008  	if !lastIP.Equal(nw.IP) {
  1009  		t.Fatalf("Wrong last IP. Expected %s. Got: %s (err: %v, ind: %d)", lastExpectedIP, nw.IP.String(), err, i)
  1010  	}
  1011  }
  1012  
  1013  func benchmarkRequest(b *testing.B, a *Allocator, subnet string) {
  1014  	pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false)
  1015  	for err != ipamapi.ErrNoAvailableIPs {
  1016  		_, _, err = a.RequestAddress(pid, nil, nil)
  1017  	}
  1018  }
  1019  
  1020  func BenchmarkRequest(b *testing.B) {
  1021  	subnets := []string{
  1022  		"10.0.0.0/24",
  1023  		"10.0.0.0/16",
  1024  		"10.0.0.0/8",
  1025  	}
  1026  
  1027  	for _, subnet := range subnets {
  1028  		name := fmt.Sprintf("%vSubnet", subnet)
  1029  		b.Run(name, func(b *testing.B) {
  1030  			a, _ := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
  1031  			benchmarkRequest(b, a, subnet)
  1032  		})
  1033  	}
  1034  }
  1035  
  1036  func TestAllocateRandomDeallocate(t *testing.T) {
  1037  	for _, store := range []bool{false, true} {
  1038  		testAllocateRandomDeallocate(t, "172.25.0.0/16", "", 384, store)
  1039  		testAllocateRandomDeallocate(t, "172.25.0.0/16", "172.25.252.0/22", 384, store)
  1040  	}
  1041  }
  1042  
  1043  func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int, store bool) {
  1044  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
  1045  	if err != nil {
  1046  		t.Fatal(err)
  1047  	}
  1048  
  1049  	pid, _, _, err := a.RequestPool(localAddressSpace, pool, subPool, nil, false)
  1050  	if err != nil {
  1051  		t.Fatal(err)
  1052  	}
  1053  
  1054  	// Allocate num ip addresses
  1055  	indices := make(map[int]*net.IPNet, num)
  1056  	allocated := make(map[string]bool, num)
  1057  	for i := 0; i < num; i++ {
  1058  		ip, _, err := a.RequestAddress(pid, nil, nil)
  1059  		if err != nil {
  1060  			t.Fatal(err)
  1061  		}
  1062  		ips := ip.String()
  1063  		if _, ok := allocated[ips]; ok {
  1064  			t.Fatalf("Address %s is already allocated", ips)
  1065  		}
  1066  		allocated[ips] = true
  1067  		indices[i] = ip
  1068  	}
  1069  	if len(indices) != len(allocated) || len(indices) != num {
  1070  		t.Fatalf("Unexpected number of allocated addresses: (%d,%d).", len(indices), len(allocated))
  1071  	}
  1072  
  1073  	seed := time.Now().Unix()
  1074  	rng := rand.New(rand.NewSource(seed))
  1075  
  1076  	// Deallocate half of the allocated addresses following a random pattern
  1077  	pattern := rng.Perm(num)
  1078  	for i := 0; i < num/2; i++ {
  1079  		idx := pattern[i]
  1080  		ip := indices[idx]
  1081  		err := a.ReleaseAddress(pid, ip.IP)
  1082  		if err != nil {
  1083  			t.Fatalf("Unexpected failure on deallocation of %s: %v.\nSeed: %d.", ip, err, seed)
  1084  		}
  1085  		delete(indices, idx)
  1086  		delete(allocated, ip.String())
  1087  	}
  1088  
  1089  	// Request a quarter of addresses
  1090  	for i := 0; i < num/2; i++ {
  1091  		ip, _, err := a.RequestAddress(pid, nil, nil)
  1092  		if err != nil {
  1093  			t.Fatal(err)
  1094  		}
  1095  		ips := ip.String()
  1096  		if _, ok := allocated[ips]; ok {
  1097  			t.Fatalf("\nAddress %s is already allocated.\nSeed: %d.", ips, seed)
  1098  		}
  1099  		allocated[ips] = true
  1100  	}
  1101  	if len(allocated) != num {
  1102  		t.Fatalf("Unexpected number of allocated addresses: %d.\nSeed: %d.", len(allocated), seed)
  1103  	}
  1104  }
  1105  
  1106  const (
  1107  	numInstances = 5
  1108  	first        = 0
  1109  )
  1110  
  1111  var (
  1112  	allocator *Allocator
  1113  	start     = make(chan struct{})
  1114  	done      sync.WaitGroup
  1115  	pools     = make([]*net.IPNet, numInstances)
  1116  )
  1117  
  1118  func runParallelTests(t *testing.T, instance int) {
  1119  	var err error
  1120  
  1121  	t.Parallel()
  1122  
  1123  	pTest := flag.Lookup("test.parallel")
  1124  	if pTest == nil {
  1125  		t.Skip("Skipped because test.parallel flag not set;")
  1126  	}
  1127  	numParallel, err := strconv.Atoi(pTest.Value.String())
  1128  	if err != nil {
  1129  		t.Fatal(err)
  1130  	}
  1131  	if numParallel < numInstances {
  1132  		t.Skip("Skipped because t.parallel was less than ", numInstances)
  1133  	}
  1134  
  1135  	// The first instance creates the allocator, gives the start
  1136  	// and finally checks the pools each instance was assigned
  1137  	if instance == first {
  1138  		allocator, err = NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
  1139  		if err != nil {
  1140  			t.Fatal(err)
  1141  		}
  1142  		done.Add(numInstances - 1)
  1143  		close(start)
  1144  	}
  1145  
  1146  	if instance != first {
  1147  		<-start
  1148  		defer done.Done()
  1149  	}
  1150  
  1151  	_, pools[instance], _, err = allocator.RequestPool(localAddressSpace, "", "", nil, false)
  1152  	if err != nil {
  1153  		t.Fatal(err)
  1154  	}
  1155  
  1156  	if instance == first {
  1157  		done.Wait()
  1158  		// Now check each instance got a different pool
  1159  		for i := 0; i < numInstances; i++ {
  1160  			for j := i + 1; j < numInstances; j++ {
  1161  				if types.CompareIPNet(pools[i], pools[j]) {
  1162  					t.Errorf("Instance %d and %d were given the same predefined pool: %v", i, j, pools)
  1163  				}
  1164  			}
  1165  		}
  1166  	}
  1167  }
  1168  
  1169  func TestRequestReleaseAddressDuplicate(t *testing.T) {
  1170  	a, err := NewAllocator(ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
  1171  	if err != nil {
  1172  		t.Fatal(err)
  1173  	}
  1174  	type IP struct {
  1175  		ip  *net.IPNet
  1176  		ref int
  1177  	}
  1178  	ips := []IP{}
  1179  	allocatedIPs := []*net.IPNet{}
  1180  
  1181  	opts := map[string]string{
  1182  		ipamapi.AllocSerialPrefix: "true",
  1183  	}
  1184  	var l sync.Mutex
  1185  
  1186  	poolID, _, _, err := a.RequestPool(localAddressSpace, "198.168.0.0/23", "", nil, false)
  1187  	if err != nil {
  1188  		t.Fatal(err)
  1189  	}
  1190  
  1191  	seed := time.Now().Unix()
  1192  	t.Logf("Random seed: %v", seed)
  1193  	rng := rand.New(rand.NewSource(seed))
  1194  
  1195  	group, ctx := errgroup.WithContext(context.Background())
  1196  outer:
  1197  	for n := 0; n < 10000; n++ {
  1198  		var c *net.IPNet
  1199  		for {
  1200  			select {
  1201  			case <-ctx.Done():
  1202  				// One of group's goroutines returned an error.
  1203  				break outer
  1204  			default:
  1205  			}
  1206  			if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil {
  1207  				break
  1208  			}
  1209  			// No addresses available. Spin until one is.
  1210  			runtime.Gosched()
  1211  		}
  1212  		l.Lock()
  1213  		ips = append(ips, IP{c, 1})
  1214  		l.Unlock()
  1215  		allocatedIPs = append(allocatedIPs, c)
  1216  		if len(allocatedIPs) > 500 {
  1217  			i := rng.Intn(len(allocatedIPs) - 1)
  1218  			ip := allocatedIPs[i]
  1219  			allocatedIPs = append(allocatedIPs[:i], allocatedIPs[i+1:]...)
  1220  
  1221  			group.Go(func() error {
  1222  				// The lifetime of an allocated address begins when RequestAddress returns, and
  1223  				// ends when ReleaseAddress is called. But we can't atomically call one of those
  1224  				// methods and append to the log (ips slice) without also synchronizing the
  1225  				// calls with each other. Synchronizing the calls would defeat the whole point
  1226  				// of this test, which is to race ReleaseAddress against RequestAddress. We have
  1227  				// no choice but to leave a small window of uncertainty open. Appending to the
  1228  				// log after ReleaseAddress returns would allow the next RequestAddress call to
  1229  				// race the log-release operation, which could result in the reallocate being
  1230  				// logged before the release, despite the release happening before the
  1231  				// reallocate: a false positive. Our only other option is to append the release
  1232  				// to the log before calling ReleaseAddress, leaving a small race window for
  1233  				// false negatives. False positives mean a flaky test, so let's err on the side
  1234  				// of false negatives. Eventually we'll get lucky with a true-positive test
  1235  				// failure or with Go's race detector if a concurrency bug exists.
  1236  				l.Lock()
  1237  				ips = append(ips, IP{ip, -1})
  1238  				l.Unlock()
  1239  				return a.ReleaseAddress(poolID, ip.IP)
  1240  			})
  1241  		}
  1242  	}
  1243  
  1244  	if err := group.Wait(); err != nil {
  1245  		t.Fatal(err)
  1246  	}
  1247  
  1248  	refMap := make(map[string]int)
  1249  	for _, ip := range ips {
  1250  		refMap[ip.ip.String()] = refMap[ip.ip.String()] + ip.ref
  1251  		if refMap[ip.ip.String()] < 0 {
  1252  			t.Fatalf("IP %s was previously released", ip.ip.String())
  1253  		}
  1254  		if refMap[ip.ip.String()] > 1 {
  1255  			t.Fatalf("IP %s was previously allocated", ip.ip.String())
  1256  		}
  1257  	}
  1258  }
  1259  
  1260  func TestParallelPredefinedRequest1(t *testing.T) {
  1261  	runParallelTests(t, 0)
  1262  }
  1263  
  1264  func TestParallelPredefinedRequest2(t *testing.T) {
  1265  	runParallelTests(t, 1)
  1266  }
  1267  
  1268  func TestParallelPredefinedRequest3(t *testing.T) {
  1269  	runParallelTests(t, 2)
  1270  }
  1271  
  1272  func TestParallelPredefinedRequest4(t *testing.T) {
  1273  	runParallelTests(t, 3)
  1274  }
  1275  
  1276  func TestParallelPredefinedRequest5(t *testing.T) {
  1277  	runParallelTests(t, 4)
  1278  }
  1279  
  1280  func BenchmarkPoolIDToString(b *testing.B) {
  1281  	const poolIDString = "default/172.27.0.0/16/172.27.3.0/24"
  1282  	k, err := PoolIDFromString(poolIDString)
  1283  	if err != nil {
  1284  		b.Fatal(err)
  1285  	}
  1286  
  1287  	b.ReportAllocs()
  1288  	for i := 0; i < b.N; i++ {
  1289  		_ = k.String()
  1290  	}
  1291  }
  1292  
  1293  func BenchmarkPoolIDFromString(b *testing.B) {
  1294  	const poolIDString = "default/172.27.0.0/16/172.27.3.0/24"
  1295  
  1296  	b.ReportAllocs()
  1297  	for i := 0; i < b.N; i++ {
  1298  		_, err := PoolIDFromString(poolIDString)
  1299  		if err != nil {
  1300  			b.Fatal(err)
  1301  		}
  1302  	}
  1303  }