summaryrefslogtreecommitdiff
path: root/vendor/github.com/cilium/ebpf/info.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/cilium/ebpf/info.go')
-rw-r--r--vendor/github.com/cilium/ebpf/info.go239
1 files changed, 239 insertions, 0 deletions
diff --git a/vendor/github.com/cilium/ebpf/info.go b/vendor/github.com/cilium/ebpf/info.go
new file mode 100644
index 000000000..b95131ef5
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/info.go
@@ -0,0 +1,239 @@
+package ebpf
+
+import (
+ "bufio"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "syscall"
+ "time"
+
+ "github.com/cilium/ebpf/internal"
+)
+
+// MapInfo describes a map.
+type MapInfo struct {
+ Type MapType
+ id MapID
+ KeySize uint32
+ ValueSize uint32
+ MaxEntries uint32
+ Flags uint32
+ // Name as supplied by user space at load time.
+ Name string
+}
+
+func newMapInfoFromFd(fd *internal.FD) (*MapInfo, error) {
+ info, err := bpfGetMapInfoByFD(fd)
+ if errors.Is(err, syscall.EINVAL) {
+ return newMapInfoFromProc(fd)
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ return &MapInfo{
+ MapType(info.map_type),
+ MapID(info.id),
+ info.key_size,
+ info.value_size,
+ info.max_entries,
+ info.map_flags,
+ // name is available from 4.15.
+ internal.CString(info.name[:]),
+ }, nil
+}
+
+func newMapInfoFromProc(fd *internal.FD) (*MapInfo, error) {
+ var mi MapInfo
+ err := scanFdInfo(fd, map[string]interface{}{
+ "map_type": &mi.Type,
+ "key_size": &mi.KeySize,
+ "value_size": &mi.ValueSize,
+ "max_entries": &mi.MaxEntries,
+ "map_flags": &mi.Flags,
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &mi, nil
+}
+
+// ID returns the map ID.
+//
+// Available from 4.13.
+//
+// The bool return value indicates whether this optional field is available.
+func (mi *MapInfo) ID() (MapID, bool) {
+ return mi.id, mi.id > 0
+}
+
+// programStats holds statistics of a program.
+type programStats struct {
+ // Total accumulated runtime of the program ins ns.
+ runtime time.Duration
+ // Total number of times the program was called.
+ runCount uint64
+}
+
+// ProgramInfo describes a program.
+type ProgramInfo struct {
+ Type ProgramType
+ id ProgramID
+ // Truncated hash of the BPF bytecode.
+ Tag string
+ // Name as supplied by user space at load time.
+ Name string
+
+ stats *programStats
+}
+
+func newProgramInfoFromFd(fd *internal.FD) (*ProgramInfo, error) {
+ info, err := bpfGetProgInfoByFD(fd)
+ if errors.Is(err, syscall.EINVAL) {
+ return newProgramInfoFromProc(fd)
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ return &ProgramInfo{
+ Type: ProgramType(info.prog_type),
+ id: ProgramID(info.id),
+ // tag is available if the kernel supports BPF_PROG_GET_INFO_BY_FD.
+ Tag: hex.EncodeToString(info.tag[:]),
+ // name is available from 4.15.
+ Name: internal.CString(info.name[:]),
+ stats: &programStats{
+ runtime: time.Duration(info.run_time_ns),
+ runCount: info.run_cnt,
+ },
+ }, nil
+}
+
+func newProgramInfoFromProc(fd *internal.FD) (*ProgramInfo, error) {
+ var info ProgramInfo
+ err := scanFdInfo(fd, map[string]interface{}{
+ "prog_type": &info.Type,
+ "prog_tag": &info.Tag,
+ })
+ if errors.Is(err, errMissingFields) {
+ return nil, &internal.UnsupportedFeatureError{
+ Name: "reading program info from /proc/self/fdinfo",
+ MinimumVersion: internal.Version{4, 10, 0},
+ }
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ return &info, nil
+}
+
+// ID returns the program ID.
+//
+// Available from 4.13.
+//
+// The bool return value indicates whether this optional field is available.
+func (pi *ProgramInfo) ID() (ProgramID, bool) {
+ return pi.id, pi.id > 0
+}
+
+// RunCount returns the total number of times the program was called.
+//
+// Can return 0 if the collection of statistics is not enabled. See EnableStats().
+// The bool return value indicates whether this optional field is available.
+func (pi *ProgramInfo) RunCount() (uint64, bool) {
+ if pi.stats != nil {
+ return pi.stats.runCount, true
+ }
+ return 0, false
+}
+
+// Runtime returns the total accumulated runtime of the program.
+//
+// Can return 0 if the collection of statistics is not enabled. See EnableStats().
+// The bool return value indicates whether this optional field is available.
+func (pi *ProgramInfo) Runtime() (time.Duration, bool) {
+ if pi.stats != nil {
+ return pi.stats.runtime, true
+ }
+ return time.Duration(0), false
+}
+
+func scanFdInfo(fd *internal.FD, fields map[string]interface{}) error {
+ raw, err := fd.Value()
+ if err != nil {
+ return err
+ }
+
+ fh, err := os.Open(fmt.Sprintf("/proc/self/fdinfo/%d", raw))
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+
+ if err := scanFdInfoReader(fh, fields); err != nil {
+ return fmt.Errorf("%s: %w", fh.Name(), err)
+ }
+ return nil
+}
+
+var errMissingFields = errors.New("missing fields")
+
+func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error {
+ var (
+ scanner = bufio.NewScanner(r)
+ scanned int
+ )
+
+ for scanner.Scan() {
+ parts := strings.SplitN(scanner.Text(), "\t", 2)
+ if len(parts) != 2 {
+ continue
+ }
+
+ name := strings.TrimSuffix(parts[0], ":")
+ field, ok := fields[string(name)]
+ if !ok {
+ continue
+ }
+
+ if n, err := fmt.Sscanln(parts[1], field); err != nil || n != 1 {
+ return fmt.Errorf("can't parse field %s: %v", name, err)
+ }
+
+ scanned++
+ }
+
+ if err := scanner.Err(); err != nil {
+ return err
+ }
+
+ if scanned != len(fields) {
+ return errMissingFields
+ }
+
+ return nil
+}
+
+// EnableStats starts the measuring of the runtime
+// and run counts of eBPF programs.
+//
+// Collecting statistics can have an impact on the performance.
+//
+// Requires at least 5.8.
+func EnableStats(which uint32) (io.Closer, error) {
+ attr := internal.BPFEnableStatsAttr{
+ StatsType: which,
+ }
+
+ fd, err := internal.BPFEnableStats(&attr)
+ if err != nil {
+ return nil, err
+ }
+ return fd, nil
+}