Repository: cilium/ebpf
Pull request #283 (2021-04-12 21:32:36)

link: introduce perfEventType

mmat11: @ti-mo CI is failing, I think it's https://github.com/cilium/ebpf/issues/117 , is there a way to rerun a test for a specific kernel version? 


Patch:
diff --git a/link/kprobe.go b/link/kprobe.go
index 9e519c2..3c1d6bd 100644
--- a/link/kprobe.go
+++ b/link/kprobe.go
@@ -158,11 +158,10 @@ func pmuKprobe(symbol string, ret bool) (*perfEvent, error) {
 
 	// Kernel has perf_kprobe PMU available, initialize perf event.
 	return &perfEvent{
-		fd:       internal.NewFD(uint32(fd)),
-		pmuID:    et,
-		name:     symbol,
-		ret:      ret,
-		progType: ebpf.Kprobe,
+		fd:    internal.NewFD(uint32(fd)),
+		pmuID: et,
+		name:  symbol,
+		typ:   kprobeEventType(ret),
 	}, nil
 }
 
@@ -214,9 +213,8 @@ func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) {
 		fd:        fd,
 		group:     group,
 		name:      symbol,
-		ret:       ret,
 		tracefsID: tid,
-		progType:  ebpf.Kprobe, // kernel only allows attaching kprobe programs to kprobe events
+		typ:       kprobeEventType(ret),
 	}, nil
 }
 
@@ -335,3 +333,10 @@ func kretprobeBit() (uint64, error) {
 	})
 	return kprobeRetprobeBit.value, kprobeRetprobeBit.err
 }
+
+func kprobeEventType(ret bool) perfEventType {
+	if ret {
+		return kretprobeEvent
+	}
+	return kprobeEvent
+}
diff --git a/link/perf_event.go b/link/perf_event.go
index de973c7..1855d1a 100644
--- a/link/perf_event.go
+++ b/link/perf_event.go
@@ -52,6 +52,14 @@ const (
 	perfAllThreads = -1
 )
 
+type perfEventType uint8
+
+const (
+	tracepointEvent perfEventType = iota
+	kprobeEvent
+	kretprobeEvent
+)
+
 // A perfEvent represents a perf event kernel object. Exactly one eBPF program
 // can be attached to it. It is created based on a tracefs trace event or a
 // Performance Monitoring Unit (PMU).
@@ -66,11 +74,10 @@ type perfEvent struct {
 	// ID of the trace event read from tracefs. Valid IDs are non-zero.
 	tracefsID uint64
 
-	// True for kretprobes/uretprobes.
-	ret bool
+	// The event type determines the types of programs that can be attached.
+	typ perfEventType
 
-	fd       *internal.FD
-	progType ebpf.ProgramType
+	fd *internal.FD
 }
 
 func (pe *perfEvent) isLink() {}
@@ -117,13 +124,13 @@ func (pe *perfEvent) Close() error {
 		return fmt.Errorf("closing perf event fd: %w", err)
 	}
 
-	switch t := pe.progType; t {
-	case ebpf.Kprobe:
+	switch pe.typ {
+	case kprobeEvent, kretprobeEvent:
 		// For kprobes created using tracefs, clean up the <tracefs>/kprobe_events entry.
 		if pe.tracefsID != 0 {
 			return closeTraceFSKprobeEvent(pe.group, pe.name)
 		}
-	case ebpf.TracePoint:
+	case tracepointEvent:
 		// Tracepoint trace events don't hold any extra resources.
 		return nil
 	}
@@ -141,12 +148,21 @@ func (pe *perfEvent) attach(prog *ebpf.Program) error {
 	if pe.fd == nil {
 		return errors.New("cannot attach to nil perf event")
 	}
-	if t := prog.Type(); t != pe.progType {
-		return fmt.Errorf("invalid program type (expected %s): %s", pe.progType, t)
-	}
 	if prog.FD() < 0 {
 		return fmt.Errorf("invalid program: %w", internal.ErrClosedFd)
 	}
+	switch pe.typ {
+	case kprobeEvent, kretprobeEvent:
+		if t := prog.Type(); t != ebpf.Kprobe {
+			return fmt.Errorf("invalid program type (expected %s): %s", ebpf.Kprobe, t)
+		}
+	case tracepointEvent:
+		if t := prog.Type(); t != ebpf.TracePoint {
+			return fmt.Errorf("invalid program type (expected %s): %s", ebpf.TracePoint, t)
+		}
+	default:
+		return fmt.Errorf("unknown perf event type: %d", pe.typ)
+	}
 
 	// The ioctl below will fail when the fd is invalid.
 	kfd, _ := pe.fd.Value()
diff --git a/link/tracepoint.go b/link/tracepoint.go
index 1652957..b8ae04b 100644
--- a/link/tracepoint.go
+++ b/link/tracepoint.go
@@ -44,7 +44,7 @@ func Tracepoint(group, name string, prog *ebpf.Program) (Link, error) {
 		tracefsID: tid,
 		group:     group,
 		name:      name,
-		progType:  ebpf.TracePoint,
+		typ:       tracepointEvent,
 	}
 
 	if err := pe.attach(prog); err != nil {


Test patch:
diff --git a/link/kprobe_test.go b/link/kprobe_test.go
index e02a141..255e3d7 100644
--- a/link/kprobe_test.go
+++ b/link/kprobe_test.go
@@ -103,14 +103,14 @@ func TestKprobeCreatePMU(t *testing.T) {
 	c.Assert(err, qt.IsNil)
 	defer pk.Close()
 
-	c.Assert(pk.progType, qt.Equals, ebpf.Kprobe)
+	c.Assert(pk.typ, qt.Equals, kprobeEvent)
 
 	// kretprobe happy path.
 	pr, err := pmuKprobe("printk", true)
 	c.Assert(err, qt.IsNil)
 	defer pr.Close()
 
-	c.Assert(pr.progType, qt.Equals, ebpf.Kprobe)
+	c.Assert(pr.typ, qt.Equals, kretprobeEvent)
 
 	// Expect os.ErrNotExist when specifying a non-existent kernel symbol
 	// on kernels 4.17 and up.
@@ -160,21 +160,22 @@ func TestKprobeTraceFS(t *testing.T) {
 	kp, err := tracefsKprobe(symbol, false)
 	c.Assert(err, qt.IsNil)
 	c.Assert(kp.Close(), qt.IsNil)
+	c.Assert(kp.typ, qt.Equals, kprobeEvent)
+
 	kp, err = tracefsKprobe(symbol, true)
 	c.Assert(err, qt.IsNil)
 	c.Assert(kp.Close(), qt.IsNil)
+	c.Assert(kp.typ, qt.Equals, kretprobeEvent)
 
 	// Create two identical trace events, ensure their IDs differ.
 	k1, err := tracefsKprobe(symbol, false)
 	c.Assert(err, qt.IsNil)
 	defer k1.Close()
-	c.Assert(k1.progType, qt.Equals, ebpf.Kprobe)
 	c.Assert(k1.tracefsID, qt.Not(qt.Equals), 0)
 
 	k2, err := tracefsKprobe(symbol, false)
 	c.Assert(err, qt.IsNil)
 	defer k2.Close()
-	c.Assert(k2.progType, qt.Equals, ebpf.Kprobe)
 	c.Assert(k2.tracefsID, qt.Not(qt.Equals), 0)
 
 	// Compare the kprobes' tracefs IDs.
diff --git a/link/tracepoint_test.go b/link/tracepoint_test.go
index 736f765..760f49d 100644
--- a/link/tracepoint_test.go
+++ b/link/tracepoint_test.go
@@ -12,12 +12,8 @@ import (
 	qt "github.com/frankban/quicktest"
 )
 
-func TestTracepoint(t *testing.T) {
-
-	// Requires at least 4.7 (98b5c2c65c29 "perf, bpf: allow bpf programs attach to tracepoints")
-	testutils.SkipOnOldKernel(t, "4.7", "tracepoint support")
-
-	prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
+var (
+	tracepointSpec = ebpf.ProgramSpec{
 		Type:    ebpf.TracePoint,
 		License: "MIT",
 		Instructions: asm.Instructions{
@@ -25,7 +21,15 @@ func TestTracepoint(t *testing.T) {
 			asm.Mov.Imm(asm.R0, 0),
 			asm.Return(),
 		},
-	})
+	}
+)
+
+func TestTracepoint(t *testing.T) {
+
+	// Requires at least 4.7 (98b5c2c65c29 "perf, bpf: allow bpf programs attach to tracepoints")
+	testutils.SkipOnOldKernel(t, "4.7", "tracepoint support")
+
+	prog, err := ebpf.NewProgram(&tracepointSpec)
 	if err != nil {
 		t.Fatal(err)
 	}