github.com/cilium/cilium@v1.16.2/pkg/identity/cache/local_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package cache
     5  
     6  import (
     7  	"fmt"
     8  	"net/netip"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  
    14  	"github.com/cilium/cilium/pkg/identity"
    15  	"github.com/cilium/cilium/pkg/labels"
    16  	"github.com/cilium/cilium/pkg/testutils"
    17  )
    18  
    19  func TestBumpNextNumericIdentity(t *testing.T) {
    20  	testutils.IntegrationTest(t)
    21  
    22  	minID, maxID := identity.NumericIdentity(1), identity.NumericIdentity(5)
    23  	scope := identity.NumericIdentity(0x42_00_00_00)
    24  	cache := newLocalIdentityCache(scope, minID, maxID, nil)
    25  
    26  	for i := minID; i <= maxID; i++ {
    27  		require.Equal(t, i, cache.nextNumericIdentity)
    28  		cache.bumpNextNumericIdentity()
    29  	}
    30  
    31  	// ID must have overflowed and must be back to minID
    32  	require.Equal(t, minID, cache.nextNumericIdentity)
    33  }
    34  
    35  func TestLocalIdentityCache(t *testing.T) {
    36  	testutils.IntegrationTest(t)
    37  
    38  	minID, maxID := identity.NumericIdentity(1), identity.NumericIdentity(5)
    39  	scope := identity.NumericIdentity(0x42_00_00_00)
    40  	cache := newLocalIdentityCache(scope, minID, maxID, nil)
    41  
    42  	identities := map[identity.NumericIdentity]*identity.Identity{}
    43  
    44  	// allocate identities for all available numeric identities with a
    45  	// unique label
    46  	for i := minID; i <= maxID; i++ {
    47  		id, isNew, err := cache.lookupOrCreate(labels.NewLabelsFromModel([]string{fmt.Sprintf("%d", i)}), identity.InvalidIdentity, false)
    48  		require.Nil(t, err)
    49  		require.Equal(t, true, isNew)
    50  		require.Equal(t, scope+i, id.ID)
    51  		identities[id.ID] = id
    52  	}
    53  
    54  	// allocate the same labels again. This must be successful and the same
    55  	// identities must be returned.
    56  	for i := minID; i <= maxID; i++ {
    57  		id, isNew, err := cache.lookupOrCreate(labels.NewLabelsFromModel([]string{fmt.Sprintf("%d", i)}), identity.InvalidIdentity, false)
    58  		require.Equal(t, false, isNew)
    59  		require.Nil(t, err)
    60  
    61  		// The returned identity must be identical
    62  		require.EqualValues(t, identities[id.ID], id)
    63  	}
    64  
    65  	// Allocation must fail as we are out of IDs
    66  	_, _, err := cache.lookupOrCreate(labels.NewLabelsFromModel([]string{"foo"}), identity.InvalidIdentity, false)
    67  	require.NotNil(t, err)
    68  
    69  	// release all identities, this must decrement the reference count but not release the identities yet
    70  	for _, id := range identities {
    71  		require.Equal(t, false, cache.release(id, false))
    72  	}
    73  
    74  	// lookup must still be successful
    75  	for i := minID; i <= maxID; i++ {
    76  		require.NotNil(t, cache.lookup(labels.NewLabelsFromModel([]string{fmt.Sprintf("%d", i)})))
    77  		require.NotNil(t, cache.lookupByID(i|scope))
    78  	}
    79  
    80  	// release the identities a second time, this must cause the identity
    81  	// to be forgotten
    82  	for _, id := range identities {
    83  		require.Equal(t, true, cache.release(id, false))
    84  	}
    85  
    86  	// allocate all identities again
    87  	for i := minID; i <= maxID; i++ {
    88  		id, isNew, err := cache.lookupOrCreate(labels.NewLabelsFromModel([]string{fmt.Sprintf("%d", i)}), identity.InvalidIdentity, false)
    89  		require.Nil(t, err)
    90  		require.Equal(t, true, isNew)
    91  		identities[id.ID] = id
    92  	}
    93  
    94  	// release a random identity in the middle
    95  	randomID := identity.NumericIdentity(3) | scope
    96  	require.Equal(t, true, cache.release(identities[randomID], false))
    97  
    98  	id, isNew, err := cache.lookupOrCreate(labels.NewLabelsFromModel([]string{"foo"}), identity.InvalidIdentity, false)
    99  	require.Nil(t, err)
   100  	require.Equal(t, true, isNew)
   101  	// the selected numeric identity must be the one released before
   102  	require.Equal(t, randomID, id.ID)
   103  }
   104  
   105  func TestOldNID(t *testing.T) {
   106  	minID, maxID := identity.NumericIdentity(1), identity.NumericIdentity(10)
   107  	scope := identity.NumericIdentity(0x42_00_00_00)
   108  	c := newLocalIdentityCache(scope, minID, maxID, nil)
   109  
   110  	// Request identity, it should work
   111  	l := labels.GetCIDRLabels(netip.MustParsePrefix("1.1.1.1/32"))
   112  	id, _, _ := c.lookupOrCreate(l, scope, false)
   113  	assert.NotNil(t, id)
   114  	assert.EqualValues(t, scope, id.ID)
   115  
   116  	// Re-request identity, it should not
   117  	l = labels.GetCIDRLabels(netip.MustParsePrefix("1.1.1.2/32"))
   118  	id, _, _ = c.lookupOrCreate(l, scope, false)
   119  	assert.NotNil(t, id)
   120  	assert.EqualValues(t, scope+1, id.ID)
   121  
   122  	// Withhold the next identity, it should be skipped
   123  	c.withhold([]identity.NumericIdentity{scope + 2})
   124  
   125  	l = labels.GetCIDRLabels(netip.MustParsePrefix("1.1.1.3/32"))
   126  	id, _, _ = c.lookupOrCreate(l, 0, false)
   127  	assert.NotNil(t, id)
   128  	assert.EqualValues(t, scope+3, id.ID)
   129  
   130  	// Request a withheld identity, it should succeed
   131  	l = labels.GetCIDRLabels(netip.MustParsePrefix("1.1.1.4/32"))
   132  	id2, _, _ := c.lookupOrCreate(l, scope+2, false)
   133  	assert.NotNil(t, id2)
   134  	assert.EqualValues(t, scope+2, id2.ID)
   135  
   136  	// Request a withheld and allocated identity, it should be ignored
   137  	l = labels.GetCIDRLabels(netip.MustParsePrefix("1.1.1.5/32"))
   138  	id, _, _ = c.lookupOrCreate(l, scope+2, false)
   139  	assert.NotNil(t, id)
   140  	assert.EqualValues(t, scope+4, id.ID)
   141  
   142  	// Unwithhold and release an identity, requesting should now succeed
   143  	c.unwithhold([]identity.NumericIdentity{scope + 2})
   144  	c.release(id2, false)
   145  	l = labels.GetCIDRLabels(netip.MustParsePrefix("1.1.1.6/32"))
   146  	id, _, _ = c.lookupOrCreate(l, scope+2, false)
   147  	assert.NotNil(t, id)
   148  	assert.EqualValues(t, scope+2, id.ID)
   149  
   150  	// Request an identity out of scope, it should not be honored
   151  	l = labels.GetCIDRLabels(netip.MustParsePrefix("1.1.1.7/32"))
   152  	id, _, _ = c.lookupOrCreate(l, scope-2, false)
   153  	assert.NotNil(t, id)
   154  	assert.EqualValues(t, scope+5, id.ID)
   155  
   156  	// Withhold all identities; allocator should fall back to a (random) withheld identity
   157  	c.withhold([]identity.NumericIdentity{scope + 6, scope + 7, scope + 8, scope + 9, scope + 10})
   158  
   159  	l = labels.GetCIDRLabels(netip.MustParsePrefix("1.1.1.8/32"))
   160  	id, _, _ = c.lookupOrCreate(l, scope-2, false)
   161  	assert.NotNil(t, id)
   162  	// actual value is random, just need it to succeed
   163  	assert.True(t, id.ID >= scope+6 && id.ID <= scope+10, "%d <= %d <= %d", scope+6, id.ID, scope+10)
   164  }