Repository: cilium/ebpf
Pull request #391 (2021-08-25 09:02:28)

features: support get map ids from program.
Signed-off-by: chenqijun <chenqijun@corp.netease.com>


Patch:
diff --git a/info.go b/info.go
index ff6f9a2..8ed505e 100644
--- a/info.go
+++ b/info.go
@@ -90,12 +90,16 @@ type ProgramInfo struct {
 	Name string
 	// BTF for the program.
 	btf btf.ID
+	// IDS map ids related to program.
+	ids []MapID
 
 	stats *programStats
 }
 
 func newProgramInfoFromFd(fd *internal.FD) (*ProgramInfo, error) {
-	info, err := bpfGetProgInfoByFD(fd)
+	const defaultNumMaps = 10
+	mapIds := make([]MapID, defaultNumMaps)
+	info, err := bpfGetProgInfoByFD(fd, mapIds)
 	if errors.Is(err, syscall.EINVAL) {
 		return newProgramInfoFromProc(fd)
 	}
@@ -103,6 +107,14 @@ func newProgramInfoFromFd(fd *internal.FD) (*ProgramInfo, error) {
 		return nil, err
 	}
 
+	if info.nr_map_ids > defaultNumMaps {
+		mapIds = make([]MapID, info.nr_map_ids)
+		info, err = bpfGetProgInfoByFD(fd, mapIds)
+		if err != nil {
+			return nil, err
+		}
+	}
+
 	return &ProgramInfo{
 		Type: ProgramType(info.prog_type),
 		id:   ProgramID(info.id),
@@ -111,6 +123,7 @@ func newProgramInfoFromFd(fd *internal.FD) (*ProgramInfo, error) {
 		// name is available from 4.15.
 		Name: internal.CString(info.name[:]),
 		btf:  btf.ID(info.btf_id),
+		ids:  mapIds[:info.nr_map_ids],
 		stats: &programStats{
 			runtime:  time.Duration(info.run_time_ns),
 			runCount: info.run_cnt,
@@ -179,6 +192,13 @@ func (pi *ProgramInfo) Runtime() (time.Duration, bool) {
 	return time.Duration(0), false
 }
 
+// MapIDs returns the maps related to the program.
+//
+// The bool return value indicates whether this optional field is available.
+func (pi *ProgramInfo) MapIDs() ([]MapID, bool) {
+	return pi.ids, pi.ids != nil
+}
+
 func scanFdInfo(fd *internal.FD, fields map[string]interface{}) error {
 	raw, err := fd.Value()
 	if err != nil {
diff --git a/prog.go b/prog.go
index ce2a27f..4ec051b 100644
--- a/prog.go
+++ b/prog.go
@@ -706,7 +706,7 @@ func ProgramGetNextID(startID ProgramID) (ProgramID, error) {
 //
 // Deprecated: use ProgramInfo.ID() instead.
 func (p *Program) ID() (ProgramID, error) {
-	info, err := bpfGetProgInfoByFD(p.fd)
+	info, err := bpfGetProgInfoByFD(p.fd, nil)
 	if err != nil {
 		return ProgramID(0), err
 	}
diff --git a/syscalls.go b/syscalls.go
index 0b85ce2..7268eb4 100644
--- a/syscalls.go
+++ b/syscalls.go
@@ -347,8 +347,13 @@ func bpfMapFreeze(m *internal.FD) error {
 	return err
 }
 
-func bpfGetProgInfoByFD(fd *internal.FD) (*bpfProgInfo, error) {
+func bpfGetProgInfoByFD(fd *internal.FD, ids []MapID) (*bpfProgInfo, error) {
 	var info bpfProgInfo
+	if len(ids) > 0 {
+		info.nr_map_ids = uint32(len(ids))
+		info.map_ids = internal.NewPointer(unsafe.Pointer(&ids[0]))
+	}
+
 	if err := internal.BPFObjGetInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)); err != nil {
 		return nil, fmt.Errorf("can't get program info: %w", err)
 	}


Test patch:
diff --git a/prog_test.go b/prog_test.go
index 1d76a20..cb9cafb 100644
--- a/prog_test.go
+++ b/prog_test.go
@@ -355,7 +355,7 @@ func TestProgramName(t *testing.T) {
 	prog := createSocketFilter(t)
 	defer prog.Close()
 
-	info, err := bpfGetProgInfoByFD(prog.fd)
+	info, err := bpfGetProgInfoByFD(prog.fd, nil)
 	if err != nil {
 		t.Fatal(err)
 	}