Skip to content
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
50 changes: 35 additions & 15 deletions info.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"os"
"reflect"
"strings"
"syscall"
"time"

"github.com/cilium/ebpf/asm"
Expand Down Expand Up @@ -258,16 +257,17 @@ type ProgramInfo struct {
numLineInfos uint32
funcInfos []byte
numFuncInfos uint32

memlock uint64
}

func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
var info sys.ProgInfo
err := sys.ObjInfo(fd, &info)
if errors.Is(err, syscall.EINVAL) {
return newProgramInfoFromProc(fd)
}
if err != nil {
return nil, err
err1 := sys.ObjInfo(fd, &info)
// EINVAL means the kernel doesn't support BPF_OBJ_GET_INFO_BY_FD. Continue
// with fdinfo if that's the case.
if err1 != nil && !errors.Is(err1, unix.EINVAL) {
return nil, fmt.Errorf("getting object info: %w", err1)
}

typ, err := ProgramTypeForPlatform(platform.Native, info.Type)
Expand All @@ -291,6 +291,17 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
verifiedInstructions: info.VerifiedInsns,
}

// Supplement OBJ_INFO with data from /proc/self/fdinfo. It contains fields
// like memlock that is not present in OBJ_INFO.
err2 := readProgramInfoFromProc(fd, &pi)
if err2 != nil && !errors.Is(err2, ErrNotSupported) {
return nil, fmt.Errorf("getting map info from fdinfo: %w", err2)
}

if err1 != nil && err2 != nil {
return nil, fmt.Errorf("ObjInfo and fdinfo both failed: objinfo: %w, fdinfo: %w", err1, err2)
}

if platform.IsWindows && info.Tag == [8]uint8{} {
// Windows doesn't support the tag field, clear it for now.
pi.Tag = ""
Expand Down Expand Up @@ -388,29 +399,29 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
return &pi, nil
}

func newProgramInfoFromProc(fd *sys.FD) (*ProgramInfo, error) {
var info ProgramInfo
func readProgramInfoFromProc(fd *sys.FD, pi *ProgramInfo) error {
var progType uint32
err := scanFdInfo(fd, map[string]interface{}{
"prog_type": &progType,
"prog_tag": &info.Tag,
"prog_tag": &pi.Tag,
"memlock": &pi.memlock,
})
if errors.Is(err, ErrNotSupported) && !errors.Is(err, internal.ErrNotSupportedOnOS) {
return nil, &internal.UnsupportedFeatureError{
return &internal.UnsupportedFeatureError{
Name: "reading program info from /proc/self/fdinfo",
MinimumVersion: internal.Version{4, 10, 0},
}
}
if err != nil {
return nil, err
return err
}

info.Type, err = ProgramTypeForPlatform(platform.Linux, progType)
pi.Type, err = ProgramTypeForPlatform(platform.Linux, progType)
if err != nil {
return nil, fmt.Errorf("program type: %w", err)
return fmt.Errorf("program type: %w", err)
}

return &info, nil
return nil
}

// ID returns the program ID.
Expand Down Expand Up @@ -743,6 +754,15 @@ func (pi *ProgramInfo) FuncInfos() (btf.FuncOffsets, error) {
)
}

// ProgramInfo returns an approximate number of bytes allocated to this program.
//
// Available from 4.10.
//
// The bool return value indicates whether this optional field is available.
func (pi *ProgramInfo) Memlock() (uint64, bool) {
return pi.memlock, pi.memlock > 0
}

func scanFdInfo(fd *sys.FD, fields map[string]interface{}) error {
if platform.IsWindows {
return fmt.Errorf("read fdinfo: %w", internal.ErrNotSupportedOnOS)
Expand Down
9 changes: 7 additions & 2 deletions info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ func validateProgInfo(t *testing.T, spec *ProgramSpec, info *ProgramInfo) {
if info.Tag != "" {
qt.Assert(t, qt.Equals(info.Tag, "d7edec644f05498d"))
}
memlock, ok := info.Memlock()
if ok {
qt.Assert(t, qt.Equals(memlock, 4096))
}
}

func TestProgramInfo(t *testing.T) {
Expand Down Expand Up @@ -161,11 +165,12 @@ func TestProgramInfoProc(t *testing.T) {
spec := fixupProgramSpec(basicProgramSpec)
prog := mustNewProgram(t, spec, nil)

info, err := newProgramInfoFromProc(prog.fd)
var info ProgramInfo
err := readProgramInfoFromProc(prog.fd, &info)
testutils.SkipIfNotSupported(t, err)
qt.Assert(t, qt.IsNil(err))

validateProgInfo(t, spec, info)
validateProgInfo(t, spec, &info)
}

func TestProgramInfoBTF(t *testing.T) {
Expand Down
Loading