github.com/cilium/cilium@v1.16.2/pkg/maps/nat/per_cluster_nat_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package nat
     5  
     6  import (
     7  	"testing"
     8  
     9  	"github.com/cilium/ebpf/rlimit"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/cilium/cilium/pkg/bpf"
    13  	cmtypes "github.com/cilium/cilium/pkg/clustermesh/types"
    14  	"github.com/cilium/cilium/pkg/option"
    15  	"github.com/cilium/cilium/pkg/testutils"
    16  )
    17  
    18  func setup(tb testing.TB) {
    19  	testutils.PrivilegedTest(tb)
    20  
    21  	bpf.CheckOrMountFS("")
    22  	require.NoError(tb, rlimit.RemoveMemlock(), "Failed to set memlock rlimit")
    23  
    24  	// Override the map names to avoid clashing with the real ones.
    25  	ClusterOuterMapNameTestOverride("test")
    26  }
    27  
    28  func path(tb testing.TB, m *bpf.Map) string {
    29  	path, err := m.Path()
    30  	require.NoError(tb, err, "Failed to retrieve map path")
    31  	return path
    32  }
    33  
    34  func TestPerClusterMaps(t *testing.T) {
    35  	setup(t)
    36  
    37  	maps := newPerClusterNATMaps(true, true, option.NATMapEntriesGlobalDefault)
    38  	require.NotNil(t, maps.v4Map, "Failed to initialize maps")
    39  	require.NotNil(t, maps.v6Map, "Failed to initialize maps")
    40  
    41  	require.NoError(t, maps.OpenOrCreate(), "Failed to create outer maps")
    42  	require.FileExists(t, path(t, maps.v4Map.Map), "Failed to create outer maps")
    43  	require.FileExists(t, path(t, maps.v6Map.Map), "Failed to create outer maps")
    44  
    45  	t.Cleanup(func() {
    46  		require.NoError(t, maps.Close())
    47  		require.NoError(t, CleanupPerClusterNATMaps(true, true), "Failed to cleanup maps")
    48  	})
    49  
    50  	// ClusterID 0 should never be used
    51  	require.Error(t, maps.CreateClusterNATMaps(0), "ClusterID 0 should never be used")
    52  	require.Error(t, maps.DeleteClusterNATMaps(0), "ClusterID 0 should never be used")
    53  	_, err := GetClusterNATMap(0, IPv4)
    54  	require.Error(t, err, "ClusterID 0 should never be used")
    55  
    56  	// ClusterID beyond the ClusterIDMax should never be used
    57  	require.Error(t, maps.CreateClusterNATMaps(cmtypes.ClusterIDMax+1), "ClusterID beyond the ClusterIDMax should never be used")
    58  	require.Error(t, maps.DeleteClusterNATMaps(cmtypes.ClusterIDMax+1), "ClusterID beyond the ClusterIDMax should never be used")
    59  	_, err = GetClusterNATMap(cmtypes.ClusterIDMax+1, IPv6)
    60  	require.Error(t, err, "ClusterID beyond the ClusterIDMax should never be used")
    61  
    62  	// Basic update
    63  	require.NoError(t, maps.CreateClusterNATMaps(1), "Failed to create maps")
    64  	require.NoError(t, maps.CreateClusterNATMaps(cmtypes.ClusterIDMax), "Failed to create maps")
    65  
    66  	for _, id := range []uint32{1, cmtypes.ClusterIDMax} {
    67  		for _, om := range []*perClusterNATMap{maps.v4Map, maps.v6Map} {
    68  			// After update, the outer map should be updated with the inner map
    69  			value, err := om.Lookup(&PerClusterNATMapKey{id})
    70  			require.NoError(t, err, "Outer map not updated correctly (id=%v, family=%v)", id, om.family)
    71  			require.NotZero(t, value, "Outer map not updated correctly (id=%v, family=%v)", id, om.family)
    72  
    73  			// After update, the inner map should exist
    74  			require.FileExists(t, path(t, &om.newInnerMap(id).Map), "Inner map not correctly present (id=%v, family=%v)", id, om.family)
    75  
    76  			// After update, it should be possible to get and open the inner map
    77  			im, err := GetClusterNATMap(id, om.family)
    78  			require.NotNil(t, im, "Failed to get inner map (id=%v, family=%v)", id, om.family)
    79  			require.NoError(t, err, "Failed to get inner map (id=%v, family=%v)", id, om.family)
    80  			require.NoError(t, im.Open(), "Failed to open inner map (id=%v, family=%v)", id, om.family)
    81  			im.Close()
    82  		}
    83  	}
    84  
    85  	// An update for an already existing entry should succeed
    86  	require.NoError(t, maps.CreateClusterNATMaps(cmtypes.ClusterIDMax), "Failed to create maps")
    87  
    88  	// Basic delete
    89  	require.NoError(t, maps.DeleteClusterNATMaps(1), "Failed to delete maps")
    90  	require.NoError(t, maps.DeleteClusterNATMaps(cmtypes.ClusterIDMax), "Failed to delete maps")
    91  
    92  	for _, id := range []uint32{1, cmtypes.ClusterIDMax} {
    93  		for _, om := range []*perClusterNATMap{maps.v4Map, maps.v6Map} {
    94  			// After delete, the outer map shouldn't contain the entry
    95  			_, err := om.Lookup(&PerClusterNATMapKey{id})
    96  			require.Error(t, err, "Outer map not updated correctly (id=%v, family=%v)", id, om.family)
    97  
    98  			// After delete, the inner map should not exist
    99  			require.NoFileExists(t, path(t, &om.newInnerMap(id).Map), "Inner map not correctly deleted (id=%v, family=%v)", id, om.family)
   100  
   101  			// After delete, it should be no longer be possible to open the inner map
   102  			im, err := GetClusterNATMap(id, om.family)
   103  			require.NotNil(t, im, "Failed to get inner map (id=%v, family=%v)", id, om.family)
   104  			require.NoError(t, err, "Failed to get inner map (id=%v, family=%v)", id, om.family)
   105  			require.Error(t, im.Open(), "Should have failed to open inner map (id=%v, family=%v)", id, om.family)
   106  		}
   107  	}
   108  
   109  	// A deletion for an already deleted entry should succeed
   110  	require.NoError(t, maps.DeleteClusterNATMaps(cmtypes.ClusterIDMax), "Failed to delete maps")
   111  }
   112  
   113  func TestPerClusterMapsCleanup(t *testing.T) {
   114  	setup(t)
   115  
   116  	tests := []struct {
   117  		name       string
   118  		ipv4, ipv6 bool
   119  	}{
   120  		{name: "IPv4", ipv4: true},
   121  		{name: "IPv6", ipv6: true},
   122  		{name: "dual", ipv4: true, ipv6: true},
   123  	}
   124  
   125  	for _, tt := range tests {
   126  		t.Run(tt.name, func(t *testing.T) {
   127  			// Pick up edge and middle values since filling all slots consumes too much memory.
   128  			ids := []uint32{1, 128, cmtypes.ClusterIDMax}
   129  			maps := newPerClusterNATMaps(true, true, option.NATMapEntriesGlobalDefault)
   130  
   131  			require.NoError(t, maps.OpenOrCreate(), "Failed to create outer maps")
   132  			t.Cleanup(func() {
   133  				require.NoError(t, maps.Close())
   134  				// This also ensures that the cleanup succeeds even if the outer maps don't exist
   135  				require.NoError(t, CleanupPerClusterNATMaps(true, true), "Failed to cleanup maps")
   136  			})
   137  
   138  			for _, id := range ids {
   139  				require.NoError(t, maps.CreateClusterNATMaps(id), "Failed to create maps (id=%v)", id)
   140  			}
   141  
   142  			require.NoError(t, CleanupPerClusterNATMaps(tt.ipv4, tt.ipv6), "Failed to cleanup maps")
   143  
   144  			for _, om := range []*perClusterNATMap{maps.v4Map, maps.v6Map} {
   145  				must := require.FileExists
   146  				if om.family == IPv4 && tt.ipv4 || om.family == IPv6 && tt.ipv6 {
   147  					must = require.NoFileExists
   148  				}
   149  
   150  				for _, id := range ids {
   151  					must(t, path(t, &om.newInnerMap(id).Map), "Inner map not correctly deleted (id=%v, family=%v)", id, om.family)
   152  				}
   153  
   154  				must(t, path(t, om.Map), "Outer map not correctly deleted (family=%v)", om.family)
   155  			}
   156  		})
   157  	}
   158  }