testdata/constants \
testdata/errors \
testdata/variables \
+ testdata/arena \
btf/testdata/relocs \
btf/testdata/relocs_read \
btf/testdata/relocs_read_tgt \
func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *btf.Spec, name string, inner bool) (*MapSpec, error) {
var (
key, value btf.Type
- keySize, valueSize uint32
+ keySize, valueSize uint64
mapType MapType
- flags, maxEntries uint32
+ flags, maxEntries uint64
pinType PinType
mapExtra uint64
innerMapSpec *MapSpec
return nil, fmt.Errorf("can't get size of BTF key: %w", err)
}
- keySize = uint32(size)
+ keySize = uint64(size)
case "value":
if valueSize != 0 {
return nil, fmt.Errorf("can't get size of BTF value: %w", err)
}
- valueSize = uint32(size)
+ valueSize = uint64(size)
case "key_size":
// Key needs to be nil and keySize needs to be 0 for key_size to be
return &MapSpec{
Name: sanitizeName(name, -1),
Type: MapType(mapType),
- KeySize: keySize,
- ValueSize: valueSize,
- MaxEntries: maxEntries,
- Flags: flags,
+ KeySize: uint32(keySize),
+ ValueSize: uint32(valueSize),
+ MaxEntries: uint32(maxEntries),
+ Flags: uint32(flags),
Key: key,
Value: value,
Pinning: pinType,
}, nil
}
-// uintFromBTF resolves the __uint macro, which is a pointer to a sized
-// array, e.g. for int (*foo)[10], this function will return 10.
-func uintFromBTF(typ btf.Type) (uint32, error) {
- ptr, ok := typ.(*btf.Pointer)
- if !ok {
- return 0, fmt.Errorf("not a pointer: %v", typ)
- }
+// uintFromBTF resolves the __uint and __ulong macros.
+//
+// __uint emits a pointer to a sized array. For int (*foo)[10], this function
+// will return 10.
+//
+// __ulong emits an enum with a single value that can represent a 64-bit
+// integer. The first (and only) enum value is returned.
+func uintFromBTF(typ btf.Type) (uint64, error) {
+ switch t := typ.(type) {
+ case *btf.Pointer:
+ arr, ok := t.Target.(*btf.Array)
+ if !ok {
+ return 0, fmt.Errorf("not a pointer to array: %v", typ)
+ }
+ return uint64(arr.Nelems), nil
- arr, ok := ptr.Target.(*btf.Array)
- if !ok {
- return 0, fmt.Errorf("not a pointer to array: %v", typ)
- }
+ case *btf.Enum:
+ if len(t.Values) == 0 {
+ return 0, errors.New("enum has no values")
+ }
+ return t.Values[0].Value, nil
- return arr.Nelems, nil
+ default:
+ return 0, fmt.Errorf("not a pointer or enum: %v", typ)
+ }
}
// resolveBTFArrayMacro resolves the __array macro, which declares an array
coll.Close()
}
+func TestArena(t *testing.T) {
+ file := testutils.NativeFile(t, "testdata/arena-%s.elf")
+ coll, err := LoadCollectionSpec(file)
+ qt.Assert(t, qt.IsNil(err))
+
+ want := &CollectionSpec{
+ Maps: map[string]*MapSpec{
+ "arena": {
+ Name: "arena",
+ Type: Arena,
+ MaxEntries: 100,
+ Flags: sys.BPF_F_MMAPABLE,
+ MapExtra: 1 << 44,
+ },
+ },
+ Programs: map[string]*ProgramSpec{},
+ Variables: map[string]*VariableSpec{},
+ }
+ qt.Assert(t, qt.CmpEquals(coll, want, csCmpOpts))
+
+ testutils.SkipOnOldKernel(t, "6.9", "arena maps")
+ mustNewCollection(t, coll, nil)
+}
+
var (
elfPath = flag.String("elfs", os.Getenv("CI_KERNEL_SELFTESTS"), "`Path` containing libbpf-compatible ELFs (defaults to $CI_KERNEL_SELFTESTS)")
elfPattern = flag.String("elf-pattern", "*.o", "Glob `pattern` for object files that should be tested")
t.Skip("Skipping since the test generates dynamic BTF")
case "test_static_linked":
t.Skip("Skipping since .text contains 'subprog' twice")
- case "bloom_filter_map", "bloom_filter_bench":
- t.Skip("Skipping due to missing MapExtra field in MapSpec")
case "netif_receive_skb",
"local_kptr_stash",
"local_kptr_stash_fail",
--- /dev/null
+/* This file excercises the ELF loader. It is not a valid BPF program. */
+
+#include "common.h"
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARENA);
+ __uint(map_flags, BPF_F_MMAPABLE);
+ __uint(max_entries, 100); /* number of pages */
+ __ulong(map_extra, 0x1ull << 44); /* start of mmap region */
+} arena __section(".maps");
TRI_MODULE = 2,
};
+#define ___bpf_concat(a, b) ____bpf_concat(a, b)
+#define ____bpf_concat(a, b) a ## b
+
#define __section(NAME) __attribute__((section(NAME), used))
#define __uint(name, val) int(*name)[val]
#define __type(name, val) typeof(val) *name
#define __array(name, val) typeof(val) *name[]
+#define __ulong(name, val) enum { ___bpf_concat(__unique_value, __COUNTER__) = val } name
#define __kconfig __attribute__((section(".kconfig")))
#define __ksym __attribute__((section(".ksyms")))
#define BPF_MAP_TYPE_PERF_EVENT_ARRAY (4)
#define BPF_MAP_TYPE_ARRAY_OF_MAPS (12)
#define BPF_MAP_TYPE_HASH_OF_MAPS (13)
+#define BPF_MAP_TYPE_ARENA (33)
#define BPF_F_NO_PREALLOC (1U << 0)
+#define BPF_F_MMAPABLE (1U << 10)
#define BPF_F_CURRENT_CPU (0xffffffffULL)
/* From tools/lib/bpf/libbpf.h */