Skip to content

Commit

Permalink
features: implement feature probe for StructOpsMap
Browse files Browse the repository at this point in the history
With the libbpf feature probe API being reworked a while back, a probe for
StructOps maps was also implemented. Setting an invalid vmlinux type id
and checking for ENOTSUPP signals the map's availability.

Signed-off-by: Timo Beckers <timo@isovalent.com>
  • Loading branch information
ti-mo committed Jul 22, 2022
1 parent 3fedca9 commit 1e9bf7a
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 34 deletions.
52 changes: 27 additions & 25 deletions features/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ type mapCache struct {

func createMapTypeAttr(mt ebpf.MapType) *sys.MapCreateAttr {
var (
keySize uint32 = 4
valueSize uint32 = 4
maxEntries uint32 = 1
innerMapFd uint32
flags uint32
btfKeyTypeID uint32
btfValueTypeID uint32
btfFd uint32
keySize uint32 = 4
valueSize uint32 = 4
maxEntries uint32 = 1
innerMapFd uint32
flags uint32
btfKeyTypeID uint32
btfValueTypeID uint32
btfVmlinuxValueTypeID uint32
btfFd uint32
)

// switch on map types to generate correct MapCreateAttr
Expand Down Expand Up @@ -80,18 +81,23 @@ func createMapTypeAttr(mt ebpf.MapType) *sys.MapCreateAttr {
btfKeyTypeID = 1 // BTF_KIND_INT
btfValueTypeID = 3 // BTF_KIND_ARRAY
btfFd = ^uint32(0)
case ebpf.StructOpsMap:
// StructOps requires setting a vmlinux type id, but id 1 will always
// be some type of integer. This will cause ENOTSUPP.
btfVmlinuxValueTypeID = 1
}

return &sys.MapCreateAttr{
MapType: sys.MapType(mt),
KeySize: keySize,
ValueSize: valueSize,
MaxEntries: maxEntries,
InnerMapFd: innerMapFd,
MapFlags: flags,
BtfKeyTypeId: btfKeyTypeID,
BtfValueTypeId: btfValueTypeID,
BtfFd: btfFd,
MapType: sys.MapType(mt),
KeySize: keySize,
ValueSize: valueSize,
MaxEntries: maxEntries,
InnerMapFd: innerMapFd,
MapFlags: flags,
BtfKeyTypeId: btfKeyTypeID,
BtfValueTypeId: btfValueTypeID,
BtfVmlinuxValueTypeId: btfVmlinuxValueTypeID,
BtfFd: btfFd,
}
}

Expand All @@ -110,14 +116,6 @@ func validateMaptype(mt ebpf.MapType) error {
if mt > mt.Max() {
return os.ErrInvalid
}

if mt == ebpf.StructOpsMap {
// A probe for StructOpsMap has vmlinux BTF requirements we currently
// cannot meet. Once we figure out how to add a working probe in this
// package, we can remove this check.
return errors.New("a probe for MapType StructOpsMap isn't implemented")
}

return nil
}

Expand All @@ -138,6 +136,10 @@ func haveMapType(mt ebpf.MapType) error {
err = nil
}

// ENOTSUPP means the map type is at least known to the kernel.
case errors.Is(err, unix.ENOTSUPP):
err = nil

// EINVAL occurs when attempting to create a map with an unknown type.
// E2BIG occurs when MapCreateAttr contains non-zero bytes past the end
// of the struct known by the running kernel, meaning the kernel is too old
Expand Down
10 changes: 1 addition & 9 deletions features/map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var mapTypeMinVersion = map[ebpf.MapType]string{
ebpf.Stack: "4.20",
ebpf.SkStorage: "5.2",
ebpf.DevMapHash: "5.4",
ebpf.StructOpsMap: "5.6", // requires vmlinux BTF, skip for now
ebpf.StructOpsMap: "5.6",
ebpf.RingBuf: "5.8",
ebpf.InodeStorage: "5.10",
ebpf.TaskStorage: "5.11",
Expand All @@ -54,10 +54,6 @@ func TestHaveMapType(t *testing.T) {
feature := fmt.Sprintf("map type %s", mt.String())

t.Run(mt.String(), func(t *testing.T) {
if mt == ebpf.StructOpsMap {
t.Skip("Test for map type StructOpsMap requires working probe")
}

testutils.SkipOnOldKernel(t, minVersion, feature)

if err := HaveMapType(mt); err != nil {
Expand All @@ -79,8 +75,4 @@ func TestHaveMapTypeInvalid(t *testing.T) {
if err := HaveMapType(ebpf.MapType(math.MaxUint32)); err != os.ErrInvalid {
t.Fatalf("Expected os.ErrInvalid but was: %v", err)
}

if err := HaveMapType(ebpf.MapType(ebpf.StructOpsMap)); err == nil {
t.Fatal("Expected but was nil")
}
}

0 comments on commit 1e9bf7a

Please sign in to comment.