github.com/cilium/ebpf@v0.10.0/elf_reader_test.go (about) 1 package ebpf 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "flag" 8 "fmt" 9 "os" 10 "path/filepath" 11 "strings" 12 "syscall" 13 "testing" 14 15 "github.com/cilium/ebpf/btf" 16 "github.com/cilium/ebpf/internal" 17 "github.com/cilium/ebpf/internal/testutils" 18 "github.com/cilium/ebpf/internal/unix" 19 20 "github.com/google/go-cmp/cmp" 21 "github.com/google/go-cmp/cmp/cmpopts" 22 ) 23 24 func TestLoadCollectionSpec(t *testing.T) { 25 cpus, err := internal.PossibleCPUs() 26 if err != nil { 27 t.Fatal(err) 28 } 29 30 coll := &CollectionSpec{ 31 Maps: map[string]*MapSpec{ 32 "hash_map": { 33 Name: "hash_map", 34 Type: Hash, 35 KeySize: 4, 36 ValueSize: 8, 37 MaxEntries: 1, 38 Flags: unix.BPF_F_NO_PREALLOC, 39 }, 40 "hash_map2": { 41 Name: "hash_map2", 42 Type: Hash, 43 KeySize: 4, 44 ValueSize: 8, 45 MaxEntries: 2, 46 }, 47 "array_of_hash_map": { 48 Name: "array_of_hash_map", 49 Type: ArrayOfMaps, 50 KeySize: 4, 51 MaxEntries: 2, 52 }, 53 "perf_event_array": { 54 Name: "perf_event_array", 55 Type: PerfEventArray, 56 MaxEntries: uint32(cpus), 57 }, 58 // Maps prefixed by btf_ are ignored when testing ELFs 59 // that don't have BTF info embedded. (clang<9) 60 "btf_pin": { 61 Name: "btf_pin", 62 Type: Hash, 63 KeySize: 4, 64 ValueSize: 8, 65 MaxEntries: 1, 66 Pinning: PinByName, 67 }, 68 "btf_outer_map": { 69 Name: "btf_outer_map", 70 Type: ArrayOfMaps, 71 KeySize: 4, 72 ValueSize: 4, 73 MaxEntries: 1, 74 InnerMap: &MapSpec{ 75 Name: "btf_outer_map_inner", 76 Type: Hash, 77 KeySize: 4, 78 ValueSize: 4, 79 MaxEntries: 1, 80 }, 81 }, 82 "btf_outer_map_anon": { 83 Name: "btf_outer_map_anon", 84 Type: ArrayOfMaps, 85 KeySize: 4, 86 ValueSize: 4, 87 MaxEntries: 1, 88 InnerMap: &MapSpec{ 89 Name: "btf_outer_map_anon_inner", 90 Type: Hash, 91 KeySize: 4, 92 ValueSize: 4, 93 MaxEntries: 1, 94 }, 95 }, 96 }, 97 Programs: map[string]*ProgramSpec{ 98 "xdp_prog": { 99 Name: "xdp_prog", 100 Type: XDP, 101 SectionName: "xdp", 102 License: "MIT", 103 }, 104 "no_relocation": { 105 Name: "no_relocation", 106 Type: SocketFilter, 107 SectionName: "socket", 108 License: "MIT", 109 }, 110 "asm_relocation": { 111 Name: "asm_relocation", 112 Type: SocketFilter, 113 SectionName: "socket/2", 114 License: "MIT", 115 }, 116 "data_sections": { 117 Name: "data_sections", 118 Type: SocketFilter, 119 SectionName: "socket/3", 120 License: "MIT", 121 }, 122 "global_fn3": { 123 Name: "global_fn3", 124 Type: UnspecifiedProgram, 125 SectionName: "other", 126 License: "MIT", 127 }, 128 "static_fn": { 129 Name: "static_fn", 130 Type: UnspecifiedProgram, 131 SectionName: "static", 132 License: "MIT", 133 }, 134 "anon_const": { 135 Name: "anon_const", 136 Type: SocketFilter, 137 SectionName: "socket/4", 138 License: "MIT", 139 }, 140 }, 141 } 142 143 defaultOpts := cmp.Options{ 144 // Dummy Comparer that works with empty readers to support test cases. 145 cmp.Comparer(func(a, b bytes.Reader) bool { 146 if a.Len() == 0 && b.Len() == 0 { 147 return true 148 } 149 return false 150 }), 151 cmpopts.IgnoreTypes(new(btf.Spec)), 152 cmpopts.IgnoreFields(CollectionSpec{}, "ByteOrder", "Types"), 153 cmpopts.IgnoreFields(ProgramSpec{}, "Instructions", "ByteOrder"), 154 cmpopts.IgnoreFields(MapSpec{}, "Key", "Value"), 155 cmpopts.IgnoreUnexported(ProgramSpec{}), 156 cmpopts.IgnoreMapEntries(func(key string, _ *MapSpec) bool { 157 if key == ".bss" || key == ".data" || strings.HasPrefix(key, ".rodata") { 158 return true 159 } 160 return false 161 }), 162 } 163 164 ignoreBTFOpts := append(defaultOpts, 165 cmpopts.IgnoreMapEntries(func(key string, _ *MapSpec) bool { 166 return strings.HasPrefix(key, "btf_") 167 }), 168 ) 169 170 testutils.Files(t, testutils.Glob(t, "testdata/loader-*.elf"), func(t *testing.T, file string) { 171 have, err := LoadCollectionSpec(file) 172 if err != nil { 173 t.Fatal("Can't parse ELF:", err) 174 } 175 176 opts := defaultOpts 177 if have.Types != nil { 178 err := have.RewriteConstants(map[string]interface{}{ 179 "arg": uint32(1), 180 "arg2": uint32(2), 181 }) 182 if err != nil { 183 t.Fatal("Can't rewrite constant:", err) 184 } 185 186 err = have.RewriteConstants(map[string]interface{}{ 187 "totallyBogus": uint32(1), 188 }) 189 if err == nil { 190 t.Error("Rewriting a bogus constant doesn't fail") 191 } 192 } else { 193 opts = ignoreBTFOpts 194 } 195 196 if diff := cmp.Diff(coll, have, opts...); diff != "" { 197 t.Errorf("MapSpec mismatch (-want +got):\n%s", diff) 198 } 199 200 if have.ByteOrder != internal.NativeEndian { 201 return 202 } 203 204 have.Maps["array_of_hash_map"].InnerMap = have.Maps["hash_map"] 205 coll, err := NewCollectionWithOptions(have, CollectionOptions{ 206 Maps: MapOptions{ 207 PinPath: testutils.TempBPFFS(t), 208 }, 209 Programs: ProgramOptions{ 210 LogLevel: LogLevelBranch, 211 }, 212 }) 213 testutils.SkipIfNotSupported(t, err) 214 if err != nil { 215 t.Fatal(err) 216 } 217 defer coll.Close() 218 219 ret, _, err := coll.Programs["xdp_prog"].Test(internal.EmptyBPFContext) 220 if err != nil { 221 t.Fatal("Can't run program:", err) 222 } 223 224 if ret != 7 { 225 t.Error("Expected return value to be 5, got", ret) 226 } 227 }) 228 } 229 230 func BenchmarkELFLoader(b *testing.B) { 231 b.ReportAllocs() 232 233 for i := 0; i < b.N; i++ { 234 _, _ = LoadCollectionSpec("testdata/loader-el.elf") 235 } 236 } 237 238 func TestDataSections(t *testing.T) { 239 file := fmt.Sprintf("testdata/loader-%s.elf", internal.ClangEndian) 240 coll, err := LoadCollectionSpec(file) 241 if err != nil { 242 t.Fatal(err) 243 } 244 245 t.Log(coll.Programs["data_sections"].Instructions) 246 247 var obj struct { 248 Program *Program `ebpf:"data_sections"` 249 } 250 251 err = coll.LoadAndAssign(&obj, nil) 252 testutils.SkipIfNotSupported(t, err) 253 if err != nil { 254 t.Fatal(err) 255 } 256 defer obj.Program.Close() 257 258 ret, _, err := obj.Program.Test(internal.EmptyBPFContext) 259 if err != nil { 260 t.Fatal(err) 261 } 262 263 if ret != 0 { 264 t.Error("BPF assertion failed on line", ret) 265 } 266 } 267 268 func TestInlineASMConstant(t *testing.T) { 269 file := fmt.Sprintf("testdata/loader-%s.elf", internal.ClangEndian) 270 coll, err := LoadCollectionSpec(file) 271 if err != nil { 272 t.Fatal(err) 273 } 274 275 spec := coll.Programs["asm_relocation"] 276 if spec.Instructions[0].Reference() != "MY_CONST" { 277 t.Fatal("First instruction is not a reference to MY_CONST") 278 } 279 280 // -1 is used by the loader to find unrewritten maps. 281 spec.Instructions[0].Constant = -1 282 283 t.Log(spec.Instructions) 284 285 var obj struct { 286 Program *Program `ebpf:"asm_relocation"` 287 } 288 289 err = coll.LoadAndAssign(&obj, nil) 290 testutils.SkipIfNotSupported(t, err) 291 if err != nil { 292 t.Fatal(err) 293 } 294 obj.Program.Close() 295 } 296 297 func TestCollectionSpecDetach(t *testing.T) { 298 coll := Collection{ 299 Maps: map[string]*Map{ 300 "foo": new(Map), 301 }, 302 Programs: map[string]*Program{ 303 "bar": new(Program), 304 }, 305 } 306 307 foo := coll.DetachMap("foo") 308 if foo == nil { 309 t.Error("Program not returned from DetachMap") 310 } 311 312 if _, ok := coll.Programs["foo"]; ok { 313 t.Error("DetachMap doesn't remove map from Maps") 314 } 315 316 bar := coll.DetachProgram("bar") 317 if bar == nil { 318 t.Fatal("Program not returned from DetachProgram") 319 } 320 321 if _, ok := coll.Programs["bar"]; ok { 322 t.Error("DetachProgram doesn't remove program from Programs") 323 } 324 } 325 326 func TestLoadInvalidMap(t *testing.T) { 327 testutils.Files(t, testutils.Glob(t, "testdata/invalid_map-*.elf"), func(t *testing.T, file string) { 328 cs, err := LoadCollectionSpec(file) 329 if err != nil { 330 t.Fatal("Can't load CollectionSpec", err) 331 } 332 333 ms, ok := cs.Maps["invalid_map"] 334 if !ok { 335 t.Fatal("invalid_map not found in CollectionSpec") 336 } 337 338 m, err := NewMap(ms) 339 t.Log(err) 340 if err == nil { 341 m.Close() 342 t.Fatal("Creating a Map from a MapSpec with non-zero Extra is expected to fail.") 343 } 344 }) 345 } 346 347 func TestLoadInvalidMapMissingSymbol(t *testing.T) { 348 testutils.Files(t, testutils.Glob(t, "testdata/invalid_map_static-el.elf"), func(t *testing.T, file string) { 349 _, err := LoadCollectionSpec(file) 350 t.Log(err) 351 if err == nil { 352 t.Fatal("Loading a map with static qualifier should fail") 353 } 354 }) 355 } 356 357 func TestLoadInitializedBTFMap(t *testing.T) { 358 testutils.Files(t, testutils.Glob(t, "testdata/btf_map_init-*.elf"), func(t *testing.T, file string) { 359 coll, err := LoadCollectionSpec(file) 360 if err != nil { 361 t.Fatal(err) 362 } 363 364 t.Run("NewCollection", func(t *testing.T) { 365 if coll.ByteOrder != internal.NativeEndian { 366 t.Skipf("Skipping %s collection", coll.ByteOrder) 367 } 368 369 tmp, err := NewCollection(coll) 370 testutils.SkipIfNotSupported(t, err) 371 if err != nil { 372 t.Fatal("NewCollection failed:", err) 373 } 374 tmp.Close() 375 }) 376 377 t.Run("prog_array", func(t *testing.T) { 378 m, ok := coll.Maps["prog_array_init"] 379 if !ok { 380 t.Fatal("map prog_array_init not found in program") 381 } 382 383 if len(m.Contents) != 1 { 384 t.Error("expecting exactly 1 item in MapSpec contents") 385 } 386 387 p := m.Contents[0] 388 if cmp.Equal(p.Key, 1) { 389 t.Errorf("expecting MapSpec entry Key to equal 1, got %v", p.Key) 390 } 391 392 if _, ok := p.Value.(string); !ok { 393 t.Errorf("expecting MapSpec entry Value to be a string, got %T", p.Value) 394 } 395 396 if p.Value != "tail_1" { 397 t.Errorf("expected MapSpec entry Value 'tail_1', got: %s", p.Value) 398 } 399 }) 400 401 t.Run("array_of_maps", func(t *testing.T) { 402 m, ok := coll.Maps["outer_map_init"] 403 if !ok { 404 t.Fatal("map outer_map_init not found in program") 405 } 406 407 if len(m.Contents) != 1 { 408 t.Error("expecting exactly 1 item in MapSpec contents") 409 } 410 411 if m.Key == nil { 412 t.Error("Expected non-nil key") 413 } 414 415 if m.Value == nil { 416 t.Error("Expected non-nil value") 417 } 418 419 if m.InnerMap.Key == nil { 420 t.Error("Expected non-nil InnerMap key") 421 } 422 423 if m.InnerMap.Value == nil { 424 t.Error("Expected non-nil InnerMap value") 425 } 426 427 p := m.Contents[0] 428 if cmp.Equal(p.Key, 1) { 429 t.Errorf("expecting MapSpec entry Key to equal 1, got %v", p.Key) 430 } 431 432 if _, ok := p.Value.(string); !ok { 433 t.Errorf("expecting MapSpec entry Value to be a string, got %T", p.Value) 434 } 435 436 if p.Value != "inner_map" { 437 t.Errorf("expected MapSpec entry Value 'inner_map', got: %s", p.Value) 438 } 439 }) 440 }) 441 } 442 443 func TestLoadInvalidInitializedBTFMap(t *testing.T) { 444 testutils.Files(t, testutils.Glob(t, "testdata/invalid_btf_map_init-*.elf"), func(t *testing.T, file string) { 445 _, err := LoadCollectionSpec(file) 446 t.Log(err) 447 if !errors.Is(err, internal.ErrNotSupported) { 448 t.Fatal("Loading an initialized BTF map should be unsupported") 449 } 450 }) 451 } 452 453 func TestStringSection(t *testing.T) { 454 file := fmt.Sprintf("testdata/strings-%s.elf", internal.ClangEndian) 455 spec, err := LoadCollectionSpec(file) 456 if err != nil { 457 t.Fatalf("load collection spec: %s", err) 458 } 459 460 for name := range spec.Maps { 461 t.Log(name) 462 } 463 464 strMap := spec.Maps[".rodata.str1.1"] 465 if strMap == nil { 466 t.Fatal("Unable to find map '.rodata.str1.1' in loaded collection") 467 } 468 469 if !strMap.Freeze { 470 t.Fatal("Read only data maps should be frozen") 471 } 472 473 if strMap.Flags != unix.BPF_F_RDONLY_PROG { 474 t.Fatal("Read only data maps should have the prog-read-only flag set") 475 } 476 477 coll, err := NewCollection(spec) 478 testutils.SkipIfNotSupported(t, err) 479 if err != nil { 480 t.Fatalf("new collection: %s", err) 481 } 482 483 prog := coll.Programs["filter"] 484 if prog == nil { 485 t.Fatal("program not found") 486 } 487 488 testMap := coll.Maps["my_map"] 489 if testMap == nil { 490 t.Fatal("test map not found") 491 } 492 493 _, err = prog.Run(&RunOptions{ 494 Data: internal.EmptyBPFContext, // Min size for XDP programs 495 }) 496 if err != nil { 497 t.Fatalf("prog run: %s", err) 498 } 499 500 key := []byte("This string is allocated in the string section\n\x00") 501 var value uint32 502 if err = testMap.Lookup(&key, &value); err != nil { 503 t.Fatalf("test map lookup: %s", err) 504 } 505 506 if value != 1 { 507 t.Fatal("Test map value not 1!") 508 } 509 } 510 511 func TestLoadRawTracepoint(t *testing.T) { 512 testutils.SkipOnOldKernel(t, "4.17", "BPF_RAW_TRACEPOINT API") 513 514 testutils.Files(t, testutils.Glob(t, "testdata/raw_tracepoint-*.elf"), func(t *testing.T, file string) { 515 spec, err := LoadCollectionSpec(file) 516 if err != nil { 517 t.Fatal("Can't parse ELF:", err) 518 } 519 520 if spec.ByteOrder != internal.NativeEndian { 521 return 522 } 523 524 coll, err := NewCollectionWithOptions(spec, CollectionOptions{ 525 Programs: ProgramOptions{ 526 LogLevel: LogLevelBranch, 527 }, 528 }) 529 testutils.SkipIfNotSupported(t, err) 530 if err != nil { 531 t.Fatal("Can't create collection:", err) 532 } 533 534 coll.Close() 535 }) 536 } 537 538 func TestTailCall(t *testing.T) { 539 testutils.Files(t, testutils.Glob(t, "testdata/btf_map_init-*.elf"), func(t *testing.T, file string) { 540 spec, err := LoadCollectionSpec(file) 541 if err != nil { 542 t.Fatal(err) 543 } 544 545 if spec.ByteOrder != internal.NativeEndian { 546 return 547 } 548 549 var obj struct { 550 TailMain *Program `ebpf:"tail_main"` 551 ProgArray *Map `ebpf:"prog_array_init"` 552 } 553 554 err = spec.LoadAndAssign(&obj, nil) 555 testutils.SkipIfNotSupported(t, err) 556 if err != nil { 557 t.Fatal(err) 558 } 559 defer obj.TailMain.Close() 560 defer obj.ProgArray.Close() 561 562 ret, _, err := obj.TailMain.Test(internal.EmptyBPFContext) 563 testutils.SkipIfNotSupported(t, err) 564 if err != nil { 565 t.Fatal(err) 566 } 567 568 // Expect the tail_1 tail call to be taken, returning value 42. 569 if ret != 42 { 570 t.Fatalf("Expected tail call to return value 42, got %d", ret) 571 } 572 }) 573 } 574 575 func TestSubprogRelocation(t *testing.T) { 576 testutils.SkipOnOldKernel(t, "5.13", "bpf_for_each_map_elem") 577 578 testutils.Files(t, testutils.Glob(t, "testdata/subprog_reloc-*.elf"), func(t *testing.T, file string) { 579 spec, err := LoadCollectionSpec(file) 580 if err != nil { 581 t.Fatal(err) 582 } 583 584 if spec.ByteOrder != internal.NativeEndian { 585 return 586 } 587 588 var obj struct { 589 Main *Program `ebpf:"fp_relocation"` 590 HashMap *Map `ebpf:"hash_map"` 591 } 592 593 err = spec.LoadAndAssign(&obj, nil) 594 testutils.SkipIfNotSupported(t, err) 595 if err != nil { 596 t.Fatal(err) 597 } 598 defer obj.Main.Close() 599 defer obj.HashMap.Close() 600 601 ret, _, err := obj.Main.Test(internal.EmptyBPFContext) 602 testutils.SkipIfNotSupported(t, err) 603 if err != nil { 604 t.Fatal(err) 605 } 606 607 if ret != 42 { 608 t.Fatalf("Expected subprog reloc to return value 42, got %d", ret) 609 } 610 }) 611 } 612 613 func TestUnassignedProgArray(t *testing.T) { 614 testutils.Files(t, testutils.Glob(t, "testdata/btf_map_init-*.elf"), func(t *testing.T, file string) { 615 spec, err := LoadCollectionSpec(file) 616 if err != nil { 617 t.Fatal(err) 618 } 619 620 if spec.ByteOrder != internal.NativeEndian { 621 return 622 } 623 624 // tail_main references a ProgArray that is not being assigned 625 // to this struct. Normally, this would clear all its entries 626 // and make any tail calls into the ProgArray result in a miss. 627 // The library needs to explicitly refuse such operations. 628 var obj struct { 629 TailMain *Program `ebpf:"tail_main"` 630 // ProgArray *Map `ebpf:"prog_array_init"` 631 } 632 633 err = spec.LoadAndAssign(&obj, nil) 634 testutils.SkipIfNotSupported(t, err) 635 if err == nil { 636 obj.TailMain.Close() 637 t.Fatal("Expecting LoadAndAssign to return error") 638 } 639 }) 640 } 641 642 func TestIPRoute2Compat(t *testing.T) { 643 testutils.Files(t, testutils.Glob(t, "testdata/iproute2_map_compat-*.elf"), func(t *testing.T, file string) { 644 spec, err := LoadCollectionSpec(file) 645 if err != nil { 646 t.Fatal("Can't parse ELF:", err) 647 } 648 649 if spec.ByteOrder != internal.NativeEndian { 650 return 651 } 652 653 ms, ok := spec.Maps["hash_map"] 654 if !ok { 655 t.Fatal("Map hash_map not found") 656 } 657 658 var id, pinning, innerID, innerIndex uint32 659 660 if ms.Extra == nil { 661 t.Fatal("missing extra bytes") 662 } 663 664 switch { 665 case binary.Read(ms.Extra, spec.ByteOrder, &id) != nil: 666 t.Fatal("missing id") 667 case binary.Read(ms.Extra, spec.ByteOrder, &pinning) != nil: 668 t.Fatal("missing pinning") 669 case binary.Read(ms.Extra, spec.ByteOrder, &innerID) != nil: 670 t.Fatal("missing inner_id") 671 case binary.Read(ms.Extra, spec.ByteOrder, &innerIndex) != nil: 672 t.Fatal("missing inner_idx") 673 } 674 675 if id != 0 || innerID != 0 || innerIndex != 0 { 676 t.Fatal("expecting id, inner_id and inner_idx to be zero") 677 } 678 679 if pinning != 2 { 680 t.Fatal("expecting pinning field to be 2 (PIN_GLOBAL_NS)") 681 } 682 683 // iproute2 (tc) pins maps in /sys/fs/bpf/tc/globals with PIN_GLOBAL_NS, 684 // which needs to be be configured in this library using MapOptions.PinPath. 685 // For the sake of the test, we use a tempdir on bpffs below. 686 ms.Pinning = PinByName 687 688 coll, err := NewCollectionWithOptions(spec, CollectionOptions{ 689 Maps: MapOptions{ 690 PinPath: testutils.TempBPFFS(t), 691 }, 692 }) 693 testutils.SkipIfNotSupported(t, err) 694 if err != nil { 695 t.Fatal("Can't create collection:", err) 696 } 697 698 coll.Close() 699 }) 700 } 701 702 var ( 703 elfPath = flag.String("elfs", os.Getenv("KERNEL_SELFTESTS"), "`Path` containing libbpf-compatible ELFs (defaults to $KERNEL_SELFTESTS)") 704 elfPattern = flag.String("elf-pattern", "*.o", "Glob `pattern` for object files that should be tested") 705 ) 706 707 func TestLibBPFCompat(t *testing.T) { 708 if *elfPath == "" { 709 // Specify the path to the directory containing the eBPF for 710 // the kernel's selftests if you want to run this test. 711 // As of 5.2 that is tools/testing/selftests/bpf/ 712 t.Skip("No path specified") 713 } 714 715 load := func(t *testing.T, spec *CollectionSpec, opts CollectionOptions, valid bool) { 716 // Disable retrying a program load with the log enabled, it leads 717 // to OOM kills. 718 opts.Programs.LogDisabled = true 719 720 for name, p := range spec.Programs { 721 if p.Type != Extension { 722 continue 723 } 724 725 targetProg, targetColl := loadTargetProgram(t, name, opts) 726 defer targetColl.Close() 727 p.AttachTarget = targetProg 728 } 729 730 coll, err := NewCollectionWithOptions(spec, opts) 731 testutils.SkipIfNotSupported(t, err) 732 var errno syscall.Errno 733 if errors.As(err, &errno) { 734 // This error is most likely from a syscall and caused by us not 735 // replicating some fixups done in the selftests or the test 736 // intentionally failing. This is expected, so skip the test 737 // instead of failing. 738 t.Skip("Skipping since the kernel rejected the program:", err) 739 } 740 if err == nil { 741 coll.Close() 742 } 743 if !valid { 744 if err == nil { 745 t.Fatal("Expected an error during load") 746 } 747 } else if err != nil { 748 t.Fatal("Error during loading:", err) 749 } 750 } 751 752 files := testutils.Glob(t, filepath.Join(*elfPath, *elfPattern), 753 // These files are only used as a source of btf. 754 "btf__core_reloc_*", 755 ) 756 757 testutils.Files(t, files, func(t *testing.T, path string) { 758 file := filepath.Base(path) 759 switch file { 760 case "test_map_in_map.o", "test_map_in_map.linked3.o", 761 "test_select_reuseport_kern.o", "test_select_reuseport_kern.linked3.o": 762 t.Skip("Skipping due to missing InnerMap in map definition") 763 case "test_core_autosize.o": 764 t.Skip("Skipping since the test generates dynamic BTF") 765 case "test_static_linked.linked3.o": 766 t.Skip("Skipping since .text contains 'subprog' twice") 767 case "linked_maps.linked3.o", "linked_funcs.linked3.o": 768 t.Skip("Skipping since weak relocations are not supported") 769 case "bloom_filter_map.o", "bloom_filter_map.linked3.o", 770 "bloom_filter_bench.o", "bloom_filter_bench.linked3.o": 771 t.Skip("Skipping due to missing MapExtra field in MapSpec") 772 case "netif_receive_skb.linked3.o": 773 t.Skip("Skipping due to possible bug in upstream CO-RE generation") 774 case "test_usdt.o", "test_usdt.linked3.o", "test_urandom_usdt.o", "test_urandom_usdt.linked3.o", "test_usdt_multispec.o": 775 t.Skip("Skipping due to missing support for usdt.bpf.h") 776 } 777 778 t.Parallel() 779 780 spec, err := LoadCollectionSpec(path) 781 testutils.SkipIfNotSupported(t, err) 782 if err != nil { 783 t.Fatalf("Can't read %s: %s", file, err) 784 } 785 786 switch file { 787 case "test_sk_assign.o": 788 // Test contains a legacy iproute2 bpf_elf_map definition. 789 for _, m := range spec.Maps { 790 if m.Extra == nil || m.Extra.Len() == 0 { 791 t.Fatalf("Expected extra bytes in map %s", m.Name) 792 } 793 m.Extra = nil 794 } 795 } 796 797 var opts CollectionOptions 798 for _, mapSpec := range spec.Maps { 799 if mapSpec.Pinning != PinNone { 800 opts.Maps.PinPath = testutils.TempBPFFS(t) 801 break 802 } 803 } 804 805 coreFiles := sourceOfBTF(t, path) 806 if len(coreFiles) == 0 { 807 // NB: test_core_reloc_kernel.o doesn't have dedicated BTF and 808 // therefore goes via this code path. 809 load(t, spec, opts, true) 810 return 811 } 812 813 for _, coreFile := range coreFiles { 814 name := filepath.Base(coreFile) 815 t.Run(name, func(t *testing.T) { 816 // Some files like btf__core_reloc_arrays___err_too_small.o 817 // trigger an error on purpose. Use the name to infer whether 818 // the test should succeed. 819 var valid bool 820 switch name { 821 case "btf__core_reloc_existence___err_wrong_arr_kind.o", 822 "btf__core_reloc_existence___err_wrong_arr_value_type.o", 823 "btf__core_reloc_existence___err_wrong_int_kind.o", 824 "btf__core_reloc_existence___err_wrong_int_sz.o", 825 "btf__core_reloc_existence___err_wrong_int_type.o", 826 "btf__core_reloc_existence___err_wrong_struct_type.o": 827 // These tests are buggy upstream, see https://lore.kernel.org/bpf/20210420111639.155580-1-lmb@cloudflare.com/ 828 valid = true 829 case "btf__core_reloc_ints___err_wrong_sz_16.o", 830 "btf__core_reloc_ints___err_wrong_sz_32.o", 831 "btf__core_reloc_ints___err_wrong_sz_64.o", 832 "btf__core_reloc_ints___err_wrong_sz_8.o", 833 "btf__core_reloc_arrays___err_wrong_val_type1.o", 834 "btf__core_reloc_arrays___err_wrong_val_type2.o": 835 // These tests are valid according to current libbpf behaviour, 836 // see commit 42765ede5c54ca915de5bfeab83be97207e46f68. 837 valid = true 838 case "btf__core_reloc_type_id___missing_targets.o", 839 "btf__core_reloc_flavors__err_wrong_name.o": 840 valid = false 841 case "btf__core_reloc_ints___err_bitfield.o": 842 // Bitfields are now valid. 843 valid = true 844 default: 845 valid = !strings.Contains(name, "___err_") 846 } 847 848 fh, err := os.Open(coreFile) 849 if err != nil { 850 t.Fatal(err) 851 } 852 defer fh.Close() 853 854 btfSpec, err := btf.LoadSpec(coreFile) 855 if err != nil { 856 t.Fatal(err) 857 } 858 859 opts := opts // copy 860 opts.Programs.KernelTypes = btfSpec 861 load(t, spec, opts, valid) 862 }) 863 } 864 }) 865 } 866 867 func loadTargetProgram(tb testing.TB, name string, opts CollectionOptions) (*Program, *Collection) { 868 file := "test_pkt_access.o" 869 program := "test_pkt_access" 870 switch name { 871 case "new_connect_v4_prog": 872 file = "connect4_prog.o" 873 program = "connect_v4_prog" 874 case "new_do_bind": 875 file = "connect4_prog.o" 876 program = "connect_v4_prog" 877 case "freplace_cls_redirect_test": 878 file = "test_cls_redirect.o" 879 program = "cls_redirect" 880 case "new_handle_kprobe": 881 file = "test_attach_probe.o" 882 program = "handle_kprobe" 883 case "test_pkt_md_access_new": 884 file = "test_pkt_md_access.o" 885 program = "test_pkt_md_access" 886 default: 887 } 888 889 spec, err := LoadCollectionSpec(filepath.Join(*elfPath, file)) 890 if err != nil { 891 tb.Fatalf("Can't read %s: %s", file, err) 892 } 893 894 coll, err := NewCollectionWithOptions(spec, opts) 895 if err != nil { 896 tb.Fatalf("Can't load target: %s", err) 897 } 898 899 return coll.Programs[program], coll 900 } 901 902 func sourceOfBTF(tb testing.TB, path string) []string { 903 const testPrefix = "test_core_reloc_" 904 const btfPrefix = "btf__core_reloc_" 905 906 dir, base := filepath.Split(path) 907 if !strings.HasPrefix(base, testPrefix) { 908 return nil 909 } 910 911 base = strings.TrimSuffix(base[len(testPrefix):], ".o") 912 switch base { 913 case "bitfields_direct", "bitfields_probed": 914 base = "bitfields" 915 } 916 917 return testutils.Glob(tb, filepath.Join(dir, btfPrefix+base+"*.o")) 918 } 919 920 func TestGetProgType(t *testing.T) { 921 type progTypeTestData struct { 922 Pt ProgramType 923 At AttachType 924 Fl uint32 925 To string 926 } 927 928 testcases := map[string]progTypeTestData{ 929 "socket/garbage": { 930 Pt: SocketFilter, 931 At: AttachNone, 932 To: "", 933 }, 934 "kprobe/func": { 935 Pt: Kprobe, 936 At: AttachNone, 937 To: "func", 938 }, 939 "xdp/foo": { 940 Pt: XDP, 941 At: AttachNone, 942 To: "", 943 }, 944 "xdp_devmap/foo": { 945 Pt: XDP, 946 At: AttachXDPDevMap, 947 To: "foo", 948 }, 949 "cgroup_skb/ingress": { 950 Pt: CGroupSKB, 951 At: AttachCGroupInetIngress, 952 To: "", 953 }, 954 "iter/bpf_map": { 955 Pt: Tracing, 956 At: AttachTraceIter, 957 To: "bpf_map", 958 }, 959 "lsm.s/file_ioctl_sleepable": { 960 Pt: LSM, 961 At: AttachLSMMac, 962 To: "file_ioctl_sleepable", 963 Fl: unix.BPF_F_SLEEPABLE, 964 }, 965 "lsm/file_ioctl": { 966 Pt: LSM, 967 At: AttachLSMMac, 968 To: "file_ioctl", 969 }, 970 "sk_skb/stream_verdict/foo": { 971 Pt: SkSKB, 972 At: AttachSkSKBStreamVerdict, 973 To: "", 974 }, 975 "sk_skb/bar": { 976 Pt: SkSKB, 977 At: AttachNone, 978 To: "", 979 }, 980 } 981 982 for section, want := range testcases { 983 pt, at, fl, to := getProgType(section) 984 985 if diff := cmp.Diff(want, progTypeTestData{Pt: pt, At: at, Fl: fl, To: to}); diff != "" { 986 t.Errorf("getProgType mismatch (-want +got):\n%s", diff) 987 } 988 } 989 }