github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/iterator_test.go (about) 1 package gobpfld 2 3 import ( 4 "math/rand" 5 "testing" 6 "unsafe" 7 8 "github.com/dylandreimerink/gobpfld/bpfsys" 9 "github.com/dylandreimerink/gobpfld/bpftypes" 10 "github.com/dylandreimerink/gobpfld/kernelsupport" 11 ) 12 13 var sizeOfmapIterTestKey = uint32(unsafe.Sizeof(mapIterTestKey{})) 14 15 type mapIterTestKey struct { 16 A uint32 17 B uint64 18 } 19 20 var sizeOfmapIterTestValue = uint32(unsafe.Sizeof(mapIterTestValue{})) 21 22 type mapIterTestValue struct { 23 C uint64 24 D byte 25 } 26 27 func testHashMapIteratorHappyPath(t *testing.T, hashMap *HashMap, iter MapIterator, maxEntries int) { 28 err := hashMap.Load() 29 if err != nil { 30 t.Fatal(err) 31 } 32 defer hashMap.Close() 33 34 // Just a simple go map used to verify BPF map behavior. 35 verificationMap := make(map[mapIterTestKey]mapIterTestValue, maxEntries) 36 37 // Fill the whole map verification map 38 for len(verificationMap) < maxEntries { 39 key := mapIterTestKey{ 40 A: rand.Uint32(), 41 B: rand.Uint64(), 42 } 43 44 _, ok := verificationMap[key] 45 if !ok { 46 verificationMap[key] = mapIterTestValue{ 47 C: rand.Uint64(), 48 D: byte(rand.Intn(255)), 49 } 50 } 51 } 52 53 // Copy verification map to BPF map, so contents are identical 54 for k, v := range verificationMap { 55 hashMap.Set(&k, &v, bpfsys.BPFMapElemAny) 56 } 57 58 var k mapIterTestKey 59 var v mapIterTestValue 60 err = iter.Init(&k, &v) 61 if err != nil { 62 t.Fatal(err) 63 } 64 65 for { 66 updated, err := iter.Next() 67 if err != nil { 68 t.Fatal(err) 69 } 70 if !updated { 71 break 72 } 73 74 verifyValue, ok := verificationMap[k] 75 if !ok { 76 t.Fatalf("key %v doesn't exist in verification map", k) 77 } 78 if verifyValue.C != v.C || verifyValue.D != v.D { 79 t.Fatalf("value %v from BPF map doesn't match value in verification map %v", k, verifyValue) 80 } 81 82 // Delete key from verification map, so we know we have read it exactly once 83 delete(verificationMap, k) 84 } 85 86 if len(verificationMap) > 0 { 87 t.Fatalf("not all values in verification map have been read, %d still left", len(verificationMap)) 88 } 89 } 90 91 func TestSingleLookupIteratorHappyPath(t *testing.T) { 92 const maxEntries = 128 93 hashMap := HashMap{ 94 AbstractMap: AbstractMap{ 95 Name: MustNewObjName("test"), 96 Definition: BPFMapDef{ 97 Type: bpftypes.BPF_MAP_TYPE_HASH, 98 KeySize: sizeOfmapIterTestKey, 99 ValueSize: sizeOfmapIterTestValue, 100 MaxEntries: maxEntries, 101 }, 102 }, 103 } 104 iter := &singleLookupIterator{ 105 BPFMap: &hashMap, 106 } 107 108 testHashMapIteratorHappyPath(t, &hashMap, iter, maxEntries) 109 } 110 111 func TestBatchLookupIteratorHappyPath(t *testing.T) { 112 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapBatchOps) { 113 t.Skip("Skip because the feature is not supported by current kernel version") 114 } 115 116 const maxEntries = 128 117 hashMap := HashMap{ 118 AbstractMap: AbstractMap{ 119 Name: MustNewObjName("test"), 120 Definition: BPFMapDef{ 121 Type: bpftypes.BPF_MAP_TYPE_HASH, 122 KeySize: sizeOfmapIterTestKey, 123 ValueSize: sizeOfmapIterTestValue, 124 MaxEntries: maxEntries, 125 }, 126 }, 127 } 128 iter := &batchLookupIterator{ 129 BPFMap: &hashMap, 130 } 131 132 testHashMapIteratorHappyPath(t, &hashMap, iter, maxEntries) 133 } 134 135 func TestIterForEachHappyPath(t *testing.T) { 136 const maxEntries = 128 137 arrayMap := ArrayMap{ 138 AbstractMap: AbstractMap{ 139 Name: MustNewObjName("test"), 140 Definition: BPFMapDef{ 141 Type: bpftypes.BPF_MAP_TYPE_ARRAY, 142 KeySize: 4, // Array maps always have 32bit keys (4 bytes) 143 ValueSize: sizeOfmapIterTestValue, 144 MaxEntries: maxEntries, 145 }, 146 }, 147 } 148 149 err := arrayMap.Load() 150 if err != nil { 151 t.Fatal(err) 152 } 153 defer arrayMap.Close() 154 155 // Just a simple go map used to verify BPF map behavior. 156 verificationMap := make([]mapIterTestValue, maxEntries) 157 158 // Fill the whole map verification map 159 for i := 0; i < maxEntries; i++ { 160 verificationMap[i] = mapIterTestValue{ 161 C: rand.Uint64(), 162 D: byte(rand.Intn(255)), 163 } 164 } 165 166 // Copy verification map to BPF map, so contents are identical 167 for k, v := range verificationMap { 168 err := arrayMap.Set(uint32(k), &v, bpfsys.BPFMapElemAny) 169 if err != nil { 170 t.Fatal(err) 171 } 172 } 173 174 readMap := make([]bool, len(verificationMap)) 175 176 var k uint32 177 var v mapIterTestValue 178 MapIterForEach(arrayMap.Iterator(), &k, &v, func(key, value interface{}) error { 179 if int(k) >= len(verificationMap) { 180 t.Fatalf("key %v doesn't exist in verification map", k) 181 } 182 verifyValue := verificationMap[k] 183 if verifyValue.C != v.C || verifyValue.D != v.D { 184 t.Fatalf("value at %d %v from BPF map doesn't match value in verification map %v", k, v, verifyValue) 185 } 186 if readMap[k] { 187 t.Fatalf("double read of same key %d", k) 188 } 189 190 readMap[k] = true 191 192 return nil 193 }) 194 195 for k, v := range readMap { 196 if !v { 197 t.Fatalf("key %d was not read", k) 198 } 199 } 200 } 201 202 func testArrayMapIteratorHappyPath(t *testing.T, arrayMap *ArrayMap, iter MapIterator, maxEntries int) { 203 err := arrayMap.Load() 204 if err != nil { 205 t.Fatal(err) 206 } 207 defer arrayMap.Close() 208 209 // Just a simple go map used to verify BPF map behavior. 210 verificationMap := make([]mapIterTestValue, maxEntries) 211 212 // Fill the whole map verification map 213 for i := 0; i < maxEntries; i++ { 214 verificationMap[i] = mapIterTestValue{ 215 C: rand.Uint64(), 216 D: byte(rand.Intn(255)), 217 } 218 } 219 220 // Copy verification map to BPF map, so contents are identical 221 for k, v := range verificationMap { 222 arrayMap.Set(uint32(k), &v, bpfsys.BPFMapElemAny) 223 } 224 225 var k uint32 226 var v mapIterTestValue 227 err = iter.Init(&k, &v) 228 if err != nil { 229 t.Fatal(err) 230 } 231 232 readMap := make([]bool, len(verificationMap)) 233 234 for { 235 updated, err := iter.Next() 236 if err != nil { 237 t.Fatal(err) 238 } 239 if !updated { 240 break 241 } 242 243 if int(k) >= len(verificationMap) { 244 t.Fatalf("key %v doesn't exist in verification map", k) 245 } 246 verifyValue := verificationMap[k] 247 if verifyValue.C != v.C || verifyValue.D != v.D { 248 t.Fatalf("value at %d %v from BPF map doesn't match value in verification map %v", k, v, verifyValue) 249 } 250 if readMap[k] { 251 t.Fatalf("double read of same key %d", k) 252 } 253 254 readMap[k] = true 255 } 256 257 for k, v := range readMap { 258 if !v { 259 t.Fatalf("key %d was not read", k) 260 } 261 } 262 } 263 264 func TestMMappedIteratorHappyPath(t *testing.T) { 265 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapMMap) { 266 t.Skip("Skip because the feature is not supported by current kernel version") 267 } 268 269 const maxEntries = 128 270 arrayMap := ArrayMap{ 271 AbstractMap: AbstractMap{ 272 Name: MustNewObjName("test"), 273 Definition: BPFMapDef{ 274 Type: bpftypes.BPF_MAP_TYPE_ARRAY, 275 KeySize: 4, // Array maps always have 32bit keys (4 bytes) 276 ValueSize: sizeOfmapIterTestValue, 277 MaxEntries: maxEntries, 278 Flags: bpftypes.BPFMapFlagsMMapable, // Must be loaded as mmappable 279 }, 280 }, 281 } 282 iter := &mmappedIterator{ 283 am: &arrayMap, 284 } 285 286 testArrayMapIteratorHappyPath(t, &arrayMap, iter, maxEntries) 287 } 288 289 func TestSingleMapIteratorHappyPath(t *testing.T) { 290 if !kernelsupport.CurrentFeatures.Map.Has(kernelsupport.KFeatMapArrayOfMaps) { 291 t.Skip("Skip because the feature is not supported by current kernel version") 292 } 293 294 const maxEntries = 8 295 arrayOfMaps := &ArrayOfMapsMap{ 296 AbstractMap: AbstractMap{ 297 Name: MustNewObjName("test"), 298 Definition: BPFMapDef{ 299 Type: bpftypes.BPF_MAP_TYPE_ARRAY_OF_MAPS, 300 KeySize: 4, // Array maps always have 32bit keys (4 bytes) 301 ValueSize: 4, // FD's is always 32bit (4 bytes) 302 MaxEntries: maxEntries, 303 }, 304 }, 305 } 306 iter := &singleMapLookupIterator{ 307 BPFMap: arrayOfMaps, 308 } 309 310 // Just a simple go map used to verify BPF map behavior. 311 verificationMap := make([]BPFMap, maxEntries) 312 313 innerDef := BPFMapDef{ 314 Type: bpftypes.BPF_MAP_TYPE_ARRAY, 315 KeySize: 4, 316 ValueSize: 8, 317 MaxEntries: 5, 318 } 319 320 // In some kernels <5.10 call inner maps must be the same size 321 if kernelsupport.CurrentFeatures.Map.Has(kernelsupport.KFeatMapDynamicInnerMap) { 322 innerDef.Flags |= bpftypes.BPFMapFlagsInnerMap 323 } 324 325 // Fill the whole map verification map 326 for i := 0; i < maxEntries; i++ { 327 verificationMap[i] = &ArrayMap{ 328 AbstractMap: AbstractMap{ 329 Name: MustNewObjName("inner"), 330 Definition: innerDef, 331 }, 332 } 333 } 334 335 // Must set the inner map def before loading 336 arrayOfMaps.InnerMapDef = innerDef 337 338 err := arrayOfMaps.Load() 339 if err != nil { 340 t.Fatal(err) 341 } 342 defer arrayOfMaps.Close() 343 344 // Copy verification map to BPF map, so contents are identical 345 for k, v := range verificationMap { 346 // Must load every inner map before it can be set in a map-in-map 347 err = v.Load() 348 if err != nil { 349 t.Fatal(err) 350 } 351 defer v.Close() 352 353 err = arrayOfMaps.Set(uint32(k), v, bpfsys.BPFMapElemAny) 354 if err != nil { 355 t.Fatal(err) 356 } 357 } 358 359 var k uint32 360 var v BPFMap 361 err = iter.Init(&k, &v) 362 if err != nil { 363 t.Fatal(err) 364 } 365 366 readMap := make([]bool, len(verificationMap)) 367 368 for { 369 updated, err := iter.Next() 370 if err != nil { 371 t.Fatal(err) 372 } 373 if !updated { 374 break 375 } 376 377 if int(k) >= len(verificationMap) { 378 t.Fatalf("key %v doesn't exist in verification map", k) 379 } 380 verifyValue := verificationMap[k] 381 if verifyValue != v { 382 t.Fatalf("value at %d %v from BPF map doesn't match value in verification map %v", k, v, verifyValue) 383 } 384 if readMap[k] { 385 t.Fatalf("double read of same key %d", k) 386 } 387 388 readMap[k] = true 389 } 390 391 for k, v := range readMap { 392 if !v { 393 t.Fatalf("key %d was not read", k) 394 } 395 } 396 } 397 398 func TestSingleMapIteratorHashOfMapHappyPath(t *testing.T) { 399 if !kernelsupport.CurrentFeatures.Map.Has(kernelsupport.KFeatMapHashOfMaps) { 400 t.Skip("Skip because the feature is not supported by current kernel version") 401 } 402 403 const maxEntries = 8 404 hashOfMaps := &HashOfMapsMap{ 405 AbstractMap: AbstractMap{ 406 Name: MustNewObjName("test"), 407 Definition: BPFMapDef{ 408 Type: bpftypes.BPF_MAP_TYPE_HASH_OF_MAPS, 409 KeySize: 4, // Array maps always have 32bit keys (4 bytes) 410 ValueSize: 4, // FD's is always 32bit (4 bytes) 411 MaxEntries: maxEntries, 412 }, 413 }, 414 } 415 iter := &singleMapLookupIterator{ 416 BPFMap: hashOfMaps, 417 } 418 419 // Just a simple go map used to verify BPF map behavior. 420 verificationMap := make([]BPFMap, maxEntries) 421 422 innerDef := BPFMapDef{ 423 Type: bpftypes.BPF_MAP_TYPE_ARRAY, 424 KeySize: 4, 425 ValueSize: 8, 426 MaxEntries: 5, 427 } 428 429 // In some kernels <5.10 call inner maps must be the same size 430 if kernelsupport.CurrentFeatures.Map.Has(kernelsupport.KFeatMapDynamicInnerMap) { 431 innerDef.Flags |= bpftypes.BPFMapFlagsInnerMap 432 } 433 434 // Fill the whole map verification map 435 for i := 0; i < maxEntries; i++ { 436 verificationMap[i] = &ArrayMap{ 437 AbstractMap: AbstractMap{ 438 Name: MustNewObjName("inner"), 439 Definition: innerDef, 440 }, 441 } 442 } 443 444 // Must set the inner map def before loading 445 hashOfMaps.InnerMapDef = innerDef 446 447 err := hashOfMaps.Load() 448 if err != nil { 449 t.Fatal(err) 450 } 451 defer hashOfMaps.Close() 452 453 // Copy verification map to BPF map, so contents are identical 454 for k, v := range verificationMap { 455 // Must load every inner map before it can be set in a map-in-map 456 err = v.Load() 457 if err != nil { 458 t.Fatal(err) 459 } 460 defer v.Close() 461 462 kCopy := uint32(k) 463 err = hashOfMaps.Set(&kCopy, v, bpfsys.BPFMapElemAny) 464 if err != nil { 465 t.Fatal(err) 466 } 467 } 468 469 var k uint32 470 var v BPFMap 471 err = iter.Init(&k, &v) 472 if err != nil { 473 t.Fatal(err) 474 } 475 476 readMap := make([]bool, len(verificationMap)) 477 478 for { 479 updated, err := iter.Next() 480 if err != nil { 481 t.Fatal(err) 482 } 483 if !updated { 484 break 485 } 486 487 if int(k) >= len(verificationMap) { 488 t.Fatalf("key %v doesn't exist in verification map", k) 489 } 490 verifyValue := verificationMap[k] 491 if verifyValue != v { 492 t.Fatalf("value at %d %v from BPF map doesn't match value in verification map %v", k, v, verifyValue) 493 } 494 if readMap[k] { 495 t.Fatalf("double read of same key %d", k) 496 } 497 498 readMap[k] = true 499 } 500 501 for k, v := range readMap { 502 if !v { 503 t.Fatalf("key %d was not read", k) 504 } 505 } 506 }