github.com/cilium/cilium@v1.16.2/pkg/maps/ctmap/per_cluster_ctmap_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package ctmap 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/testutils" 15 ) 16 17 func setup(tb testing.TB) { 18 testutils.PrivilegedTest(tb) 19 20 bpf.CheckOrMountFS("") 21 require.NoError(tb, rlimit.RemoveMemlock(), "Failed to set memlock rlimit") 22 23 // Override the map names to avoid clashing with the real ones. 24 ClusterOuterMapNameTestOverride("test") 25 } 26 27 func BenchmarkPerClusterCTMapUpdate(b *testing.B) { 28 b.StopTimer() 29 setup(b) 30 31 om := newPerClusterCTMap(mapTypeIPv4TCPGlobal) 32 require.NotNil(b, om, "Failed to initialize map") 33 34 require.NoError(b, om.OpenOrCreate(), "Failed to create outer map") 35 b.Cleanup(func() { 36 require.NoError(b, om.Close()) 37 require.NoError(b, CleanupPerClusterCTMaps(true, true), "Failed to cleanup maps") 38 }) 39 40 b.StartTimer() 41 42 for i := 0; i < b.N; i++ { 43 require.NoError(b, om.createClusterCTMap(1), "Failed to create map") 44 } 45 46 b.StopTimer() 47 } 48 49 func BenchmarkPerClusterCTMapLookup(b *testing.B) { 50 b.StopTimer() 51 setup(b) 52 53 om := newPerClusterCTMap(mapTypeIPv4TCPGlobal) 54 require.NotNil(b, om, "Failed to initialize map") 55 56 require.NoError(b, om.OpenOrCreate(), "Failed to create outer map") 57 b.Cleanup(func() { 58 require.NoError(b, om.Close()) 59 require.NoError(b, CleanupPerClusterCTMaps(true, true), "Failed to cleanup maps") 60 }) 61 62 require.NoError(b, om.createClusterCTMap(1), "Failed to create map") 63 64 b.StartTimer() 65 66 key := &PerClusterCTMapKey{1} 67 for i := 0; i < b.N; i++ { 68 _, err := om.Lookup(key) 69 require.NoError(b, err, "Failed to lookup element") 70 } 71 72 b.StopTimer() 73 } 74 75 func TestPerClusterCTMaps(t *testing.T) { 76 setup(t) 77 78 maps := NewPerClusterCTMaps(true, true) 79 for _, om := range []*PerClusterCTMap{maps.tcp4, maps.any4, maps.tcp6, maps.any6} { 80 require.NotNil(t, om, "Failed to initialize maps") 81 } 82 83 require.NoError(t, maps.OpenOrCreate(), "Failed to create outer maps") 84 for _, om := range []*PerClusterCTMap{maps.tcp4, maps.any4, maps.tcp6, maps.any6} { 85 require.FileExists(t, bpf.MapPath(om.Map.Name()), "Failed to create outer maps") 86 } 87 88 t.Cleanup(func() { 89 require.NoError(t, maps.Close()) 90 require.NoError(t, CleanupPerClusterCTMaps(true, true), "Failed to cleanup maps") 91 }) 92 93 // ClusterID 0 should never be used 94 require.Error(t, maps.CreateClusterCTMaps(0), "ClusterID 0 should never be used") 95 require.Error(t, maps.DeleteClusterCTMaps(0), "ClusterID 0 should never be used") 96 _, err := GetClusterCTMaps(0, true, true) 97 require.Error(t, err, "ClusterID 0 should never be used") 98 99 // ClusterID beyond the ClusterIDMax should never be used 100 require.Error(t, maps.CreateClusterCTMaps(cmtypes.ClusterIDMax+1), "ClusterID beyond the ClusterIDMax should never be used") 101 require.Error(t, maps.DeleteClusterCTMaps(cmtypes.ClusterIDMax+1), "ClusterID beyond the ClusterIDMax should never be used") 102 _, err = GetClusterCTMaps(cmtypes.ClusterIDMax+1, true, true) 103 require.Error(t, err, "ClusterID beyond the ClusterIDMax should never be used") 104 105 // Basic update 106 require.NoError(t, maps.CreateClusterCTMaps(1), "Failed to create maps") 107 require.NoError(t, maps.CreateClusterCTMaps(cmtypes.ClusterIDMax), "Failed to create maps") 108 109 for _, id := range []uint32{1, cmtypes.ClusterIDMax} { 110 for _, om := range []*PerClusterCTMap{maps.tcp4, maps.any4, maps.tcp6, maps.any6} { 111 // After update, the outer map should be updated with the inner map 112 value, err := om.Lookup(&PerClusterCTMapKey{id}) 113 require.NoError(t, err, "Outer map not updated correctly (id=%v, map=%v)", id, om.Name()) 114 require.NotZero(t, value, "Outer map not updated correctly (id=%v, map=%v)", id, om.Name()) 115 116 // After update, the inner map should exist 117 require.FileExists(t, bpf.MapPath(om.newInnerMap(id).Map.Name()), "Inner map not correctly present (id=%v, map=%v)", id, om.Name()) 118 } 119 120 // After update, it should be possible to get and open the inner map 121 ims, err := GetClusterCTMaps(id, true, true) 122 require.Len(t, ims, 4, "Retrieved an incorrect number of inner maps") 123 for _, im := range ims { 124 require.NotNil(t, im, "Failed to get inner map (id=%v, map=%v)", id, im.Name()) 125 require.NoError(t, err, "Failed to get inner map (id=%v, map=%v)", id, im.Name()) 126 require.NoError(t, im.Open(), "Failed to open inner map (id=%v, map=%v)", im.Name()) 127 im.Close() 128 } 129 } 130 131 // An update for an already existing entry should succeed 132 require.NoError(t, maps.CreateClusterCTMaps(cmtypes.ClusterIDMax), "Failed to create maps") 133 134 // Basic get all 135 ims := maps.GetAllClusterCTMaps() 136 require.Len(t, ims, 8, "Retrieved an unexpected number of maps") 137 138 // Basic delete 139 require.NoError(t, maps.DeleteClusterCTMaps(1), "Failed to delete maps") 140 require.NoError(t, maps.DeleteClusterCTMaps(cmtypes.ClusterIDMax), "Failed to delete maps") 141 142 for _, id := range []uint32{1, cmtypes.ClusterIDMax} { 143 for _, om := range []*PerClusterCTMap{maps.tcp4, maps.any4, maps.tcp6, maps.any6} { 144 // After delete, the outer map shouldn't contain the entry 145 _, err := om.Lookup(&PerClusterCTMapKey{id}) 146 require.Error(t, err, "Outer map not updated correctly (id=%v, map=%v)", id, om.Name()) 147 148 // After delete, the inner map should not exist 149 require.NoFileExists(t, bpf.MapPath(om.newInnerMap(id).Map.Name()), "Inner map not correctly deleted (id=%v, map=%v)", id, om.Name()) 150 } 151 152 // After delete, it should be no longer be possible to open the inner map 153 ims, err := GetClusterCTMaps(id, true, true) 154 require.Len(t, ims, 4, "Retrieved an incorrect number of inner maps") 155 for _, im := range ims { 156 require.NotNil(t, im, "Failed to get inner map (id=%v, map=%v)", id, im.Name()) 157 require.NoError(t, err, "Failed to get inner map (id=%v, map=%v)", id, im.Name()) 158 require.Error(t, im.Open(), "Should have failed to open inner map (id=%v, map=%v)", id, im.Name()) 159 } 160 } 161 162 // A deletion for an already deleted entry should succeed 163 require.NoError(t, maps.DeleteClusterCTMaps(cmtypes.ClusterIDMax), "Failed to delete maps") 164 } 165 166 func TestPerClusterCTMapsCleanup(t *testing.T) { 167 setup(t) 168 169 tests := []struct { 170 name string 171 ipv4, ipv6 bool 172 present, absent []mapType 173 }{ 174 { 175 name: "IPv4", 176 ipv4: true, 177 present: []mapType{mapTypeIPv6TCPGlobal, mapTypeIPv6AnyLocal}, 178 absent: []mapType{mapTypeIPv4TCPGlobal, mapTypeIPv4AnyLocal}, 179 }, 180 { 181 name: "IPv6", 182 ipv6: true, 183 present: []mapType{mapTypeIPv4TCPGlobal, mapTypeIPv4AnyLocal}, 184 absent: []mapType{mapTypeIPv6TCPGlobal, mapTypeIPv6AnyLocal}, 185 }, 186 { 187 name: "dual", 188 ipv4: true, 189 ipv6: true, 190 absent: []mapType{mapTypeIPv4TCPGlobal, mapTypeIPv4AnyLocal, mapTypeIPv6TCPGlobal, mapTypeIPv6AnyLocal}, 191 }, 192 } 193 194 for _, tt := range tests { 195 t.Run(tt.name, func(t *testing.T) { 196 // Pick up edge and middle values since filling all slots consumes too much memory. 197 ids := []uint32{1, 128, cmtypes.ClusterIDMax} 198 gm := NewPerClusterCTMaps(true, true) 199 200 require.NoError(t, gm.OpenOrCreate(), "Failed to create outer maps") 201 t.Cleanup(func() { 202 require.NoError(t, gm.Close()) 203 // This also ensures that the cleanup succeeds even if the outer maps don't exist 204 require.NoError(t, CleanupPerClusterCTMaps(true, true), "Failed to cleanup maps") 205 }) 206 207 for _, id := range ids { 208 require.NoError(t, gm.CreateClusterCTMaps(id), "Failed to create maps (id=%v)", id) 209 } 210 211 require.NoError(t, CleanupPerClusterCTMaps(tt.ipv4, tt.ipv6), "Failed to cleanup maps") 212 213 for _, typ := range tt.present { 214 for _, id := range ids { 215 require.FileExists(t, bpf.MapPath(ClusterInnerMapName(typ, id)), "Inner map should not have been deleted (id=%v, type=%v)", id, typ.name()) 216 } 217 require.FileExists(t, bpf.MapPath(ClusterOuterMapName(typ)), "Outer map should not have been deleted (type=%v)", typ.name()) 218 } 219 220 for _, typ := range tt.absent { 221 for _, id := range ids { 222 require.NoFileExists(t, bpf.MapPath(ClusterInnerMapName(typ, id)), "Inner map should have been deleted (id=%v, type=%v)", id, typ.name()) 223 } 224 require.NoFileExists(t, bpf.MapPath(ClusterOuterMapName(typ)), "Outer map should have been deleted (type=%v)", typ.name()) 225 } 226 }) 227 } 228 }