Skip to content

Commit dc25617

Browse files
committed
map: preliminary support for arenas
This commit teaches ebpf-go to understand the __ulong BTF map definition macro and uses it to specify a 64-bit value for map_extra in an arena map, defining the start of the mmap region for the Collection's arena. Signed-off-by: Timo Beckers <[email protected]>
1 parent 4ead5d0 commit dc25617

File tree

7 files changed

+72
-22
lines changed

7 files changed

+72
-22
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ TARGETS := \
4949
testdata/constants \
5050
testdata/errors \
5151
testdata/variables \
52+
testdata/arena \
5253
btf/testdata/relocs \
5354
btf/testdata/relocs_read \
5455
btf/testdata/relocs_read_tgt \

elf_reader.go

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -873,9 +873,9 @@ func (ec *elfCode) loadBTFMaps() error {
873873
func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *btf.Spec, name string, inner bool) (*MapSpec, error) {
874874
var (
875875
key, value btf.Type
876-
keySize, valueSize uint32
876+
keySize, valueSize uint64
877877
mapType MapType
878-
flags, maxEntries uint32
878+
flags, maxEntries uint64
879879
pinType PinType
880880
mapExtra uint64
881881
innerMapSpec *MapSpec
@@ -921,7 +921,7 @@ func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *b
921921
return nil, fmt.Errorf("can't get size of BTF key: %w", err)
922922
}
923923

924-
keySize = uint32(size)
924+
keySize = uint64(size)
925925

926926
case "value":
927927
if valueSize != 0 {
@@ -940,7 +940,7 @@ func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *b
940940
return nil, fmt.Errorf("can't get size of BTF value: %w", err)
941941
}
942942

943-
valueSize = uint32(size)
943+
valueSize = uint64(size)
944944

945945
case "key_size":
946946
// Key needs to be nil and keySize needs to be 0 for key_size to be
@@ -1061,10 +1061,10 @@ func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *b
10611061
return &MapSpec{
10621062
Name: sanitizeName(name, -1),
10631063
Type: MapType(mapType),
1064-
KeySize: keySize,
1065-
ValueSize: valueSize,
1066-
MaxEntries: maxEntries,
1067-
Flags: flags,
1064+
KeySize: uint32(keySize),
1065+
ValueSize: uint32(valueSize),
1066+
MaxEntries: uint32(maxEntries),
1067+
Flags: uint32(flags),
10681068
Key: key,
10691069
Value: value,
10701070
Pinning: pinType,
@@ -1075,20 +1075,31 @@ func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *b
10751075
}, nil
10761076
}
10771077

1078-
// uintFromBTF resolves the __uint macro, which is a pointer to a sized
1079-
// array, e.g. for int (*foo)[10], this function will return 10.
1080-
func uintFromBTF(typ btf.Type) (uint32, error) {
1081-
ptr, ok := typ.(*btf.Pointer)
1082-
if !ok {
1083-
return 0, fmt.Errorf("not a pointer: %v", typ)
1084-
}
1078+
// uintFromBTF resolves the __uint and __ulong macros.
1079+
//
1080+
// __uint emits a pointer to a sized array. For int (*foo)[10], this function
1081+
// will return 10.
1082+
//
1083+
// __ulong emits an enum with a single value that can represent a 64-bit
1084+
// integer. The first (and only) enum value is returned.
1085+
func uintFromBTF(typ btf.Type) (uint64, error) {
1086+
switch t := typ.(type) {
1087+
case *btf.Pointer:
1088+
arr, ok := t.Target.(*btf.Array)
1089+
if !ok {
1090+
return 0, fmt.Errorf("not a pointer to array: %v", typ)
1091+
}
1092+
return uint64(arr.Nelems), nil
10851093

1086-
arr, ok := ptr.Target.(*btf.Array)
1087-
if !ok {
1088-
return 0, fmt.Errorf("not a pointer to array: %v", typ)
1089-
}
1094+
case *btf.Enum:
1095+
if len(t.Values) == 0 {
1096+
return 0, errors.New("enum has no values")
1097+
}
1098+
return t.Values[0].Value, nil
10901099

1091-
return arr.Nelems, nil
1100+
default:
1101+
return 0, fmt.Errorf("not a pointer or enum: %v", typ)
1102+
}
10921103
}
10931104

10941105
// resolveBTFArrayMacro resolves the __array macro, which declares an array

elf_reader_test.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,30 @@ func TestIPRoute2Compat(t *testing.T) {
943943
coll.Close()
944944
}
945945

946+
func TestArena(t *testing.T) {
947+
file := testutils.NativeFile(t, "testdata/arena-%s.elf")
948+
coll, err := LoadCollectionSpec(file)
949+
qt.Assert(t, qt.IsNil(err))
950+
951+
want := &CollectionSpec{
952+
Maps: map[string]*MapSpec{
953+
"arena": {
954+
Name: "arena",
955+
Type: Arena,
956+
MaxEntries: 100,
957+
Flags: sys.BPF_F_MMAPABLE,
958+
MapExtra: 1 << 44,
959+
},
960+
},
961+
Programs: map[string]*ProgramSpec{},
962+
Variables: map[string]*VariableSpec{},
963+
}
964+
qt.Assert(t, qt.CmpEquals(coll, want, csCmpOpts))
965+
966+
testutils.SkipOnOldKernel(t, "6.9", "arena maps")
967+
mustNewCollection(t, coll, nil)
968+
}
969+
946970
var (
947971
elfPath = flag.String("elfs", os.Getenv("CI_KERNEL_SELFTESTS"), "`Path` containing libbpf-compatible ELFs (defaults to $CI_KERNEL_SELFTESTS)")
948972
elfPattern = flag.String("elf-pattern", "*.o", "Glob `pattern` for object files that should be tested")
@@ -997,8 +1021,6 @@ func TestLibBPFCompat(t *testing.T) {
9971021
t.Skip("Skipping since the test generates dynamic BTF")
9981022
case "test_static_linked":
9991023
t.Skip("Skipping since .text contains 'subprog' twice")
1000-
case "bloom_filter_map", "bloom_filter_bench":
1001-
t.Skip("Skipping due to missing MapExtra field in MapSpec")
10021024
case "netif_receive_skb",
10031025
"local_kptr_stash",
10041026
"local_kptr_stash_fail",

testdata/arena-eb.elf

1.09 KB
Binary file not shown.

testdata/arena-el.elf

1.09 KB
Binary file not shown.

testdata/arena.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* This file excercises the ELF loader. It is not a valid BPF program. */
2+
3+
#include "common.h"
4+
5+
struct {
6+
__uint(type, BPF_MAP_TYPE_ARENA);
7+
__uint(map_flags, BPF_F_MMAPABLE);
8+
__uint(max_entries, 100); /* number of pages */
9+
__ulong(map_extra, 0x1ull << 44); /* start of mmap region */
10+
} arena __section(".maps");

testdata/common.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@ enum libbpf_tristate {
1313
TRI_MODULE = 2,
1414
};
1515

16+
#define ___bpf_concat(a, b) ____bpf_concat(a, b)
17+
#define ____bpf_concat(a, b) a ## b
18+
1619
#define __section(NAME) __attribute__((section(NAME), used))
1720
#define __uint(name, val) int(*name)[val]
1821
#define __type(name, val) typeof(val) *name
1922
#define __array(name, val) typeof(val) *name[]
23+
#define __ulong(name, val) enum { ___bpf_concat(__unique_value, __COUNTER__) = val } name
2024

2125
#define __kconfig __attribute__((section(".kconfig")))
2226
#define __ksym __attribute__((section(".ksyms")))
@@ -40,8 +44,10 @@ enum libbpf_tristate {
4044
#define BPF_MAP_TYPE_PERF_EVENT_ARRAY (4)
4145
#define BPF_MAP_TYPE_ARRAY_OF_MAPS (12)
4246
#define BPF_MAP_TYPE_HASH_OF_MAPS (13)
47+
#define BPF_MAP_TYPE_ARENA (33)
4348

4449
#define BPF_F_NO_PREALLOC (1U << 0)
50+
#define BPF_F_MMAPABLE (1U << 10)
4551
#define BPF_F_CURRENT_CPU (0xffffffffULL)
4652

4753
/* From tools/lib/bpf/libbpf.h */

0 commit comments

Comments
 (0)