Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

map: add Map.Handle() method for retrieving a Map's type information #1488

Merged
merged 1 commit into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions info.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ type MapInfo struct {
Flags uint32
// Name as supplied by user space at load time. Available from 4.15.
Name string

btf btf.ID
}

func newMapInfoFromFd(fd *sys.FD) (*MapInfo, error) {
Expand All @@ -50,6 +52,7 @@ func newMapInfoFromFd(fd *sys.FD) (*MapInfo, error) {
info.MaxEntries,
uint32(info.MapFlags),
unix.ByteSliceToString(info.Name[:]),
btf.ID(info.BtfId),
}, nil
}

Expand Down Expand Up @@ -77,6 +80,18 @@ func (mi *MapInfo) ID() (MapID, bool) {
return mi.id, mi.id > 0
}

// BTFID returns the BTF ID associated with the Map.
//
// The ID is only valid as long as the associated Map is kept alive.
// Available from 4.18.
//
// The bool return value indicates whether this optional field is available and
// populated. (The field may be available but not populated if the kernel
// supports the field but the Map was loaded without BTF information.)
func (mi *MapInfo) BTFID() (btf.ID, bool) {
return mi.btf, mi.btf > 0
}

// programStats holds statistics of a program.
type programStats struct {
// Total accumulated runtime of the program ins ns.
Expand Down
18 changes: 18 additions & 0 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,24 @@ func (m *Map) Info() (*MapInfo, error) {
return newMapInfoFromFd(m.fd)
}

// Handle returns a reference to the Map's type information in the kernel.
//
// Returns ErrNotSupported if the kernel has no BTF support, or if there is no
// BTF associated with the Map.
func (m *Map) Handle() (*btf.Handle, error) {
info, err := m.Info()
if err != nil {
return nil, err
}

id, ok := info.BTFID()
if !ok {
return nil, fmt.Errorf("map %s: retrieve BTF ID: %w", m, ErrNotSupported)
}

return btf.NewHandleFromID(id)
}

// MapLookupFlags controls the behaviour of the map lookup calls.
type MapLookupFlags uint64

Expand Down
29 changes: 29 additions & 0 deletions map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"unsafe"

"github.com/cilium/ebpf/asm"
"github.com/cilium/ebpf/btf"
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/sys"
"github.com/cilium/ebpf/internal/testutils"
Expand Down Expand Up @@ -1791,6 +1792,34 @@ func TestMapPinning(t *testing.T) {
qt.Assert(t, qt.StringContains(err.Error(), "ValueSize"))
}

func TestMapHandle(t *testing.T) {
testutils.SkipOnOldKernel(t, "4.18", "btf_id in map info")

kv := &btf.Int{Size: 4}
m, err := NewMap(&MapSpec{
Type: Hash,
KeySize: kv.Size,
ValueSize: kv.Size,
Key: kv,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm amazed this all just works!

Value: kv,
MaxEntries: 1,
})
qt.Assert(t, qt.IsNil(err))
defer m.Close()

h, err := m.Handle()
qt.Assert(t, qt.IsNil(err))
qt.Assert(t, qt.IsNotNil(h))
defer h.Close()

spec, err := h.Spec(nil)
qt.Assert(t, qt.IsNil(err))

typ, err := spec.TypeByID(1)
qt.Assert(t, qt.IsNil(err))
qt.Assert(t, qt.ContentEquals(typ, btf.Type(kv)))
}

func TestPerfEventArrayCompatible(t *testing.T) {
ms := &MapSpec{
Type: PerfEventArray,
Expand Down
Loading