Skip to content

Commit

Permalink
program: Support Unpin operation for Program
Browse files Browse the repository at this point in the history
  • Loading branch information
aditighag authored and lmb committed Mar 18, 2021
1 parent e7491cb commit 32458a7
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 10 deletions.
44 changes: 34 additions & 10 deletions prog.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,10 @@ type Program struct {
// otherwise it is empty.
VerifierLog string

fd *internal.FD
name string
typ ProgramType
fd *internal.FD
name string
pinnedPath string
typ ProgramType
}

// NewProgram creates a new Program.
Expand Down Expand Up @@ -228,7 +229,7 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, btfs btfHandl

fd, err := bpfProgLoad(attr)
if err == nil {
return &Program{internal.CString(logBuf), fd, spec.Name, spec.Type}, nil
return &Program{internal.CString(logBuf), fd, spec.Name, "", spec.Type}, nil
}

logErr := err
Expand Down Expand Up @@ -287,7 +288,7 @@ func newProgramFromFD(fd *internal.FD) (*Program, error) {
return nil, fmt.Errorf("discover program type: %w", err)
}

return &Program{"", fd, "", info.Type}, nil
return &Program{"", fd, "", "", info.Type}, nil
}

func (p *Program) String() string {
Expand Down Expand Up @@ -338,19 +339,42 @@ func (p *Program) Clone() (*Program, error) {
return nil, fmt.Errorf("can't clone program: %w", err)
}

return &Program{p.VerifierLog, dup, p.name, p.typ}, nil
return &Program{p.VerifierLog, dup, p.name, "", p.typ}, nil
}

// Pin persists the Program past the lifetime of the process that created it
// Pin persists the Program on the BPF virtual file system past the lifetime of
// the process that created it
//
// This requires bpffs to be mounted above fileName. See https://docs.cilium.io/en/k8s-doc/admin/#admin-mount-bpffs
func (p *Program) Pin(fileName string) error {
if err := internal.BPFObjPin(fileName, p.fd); err != nil {
return fmt.Errorf("can't pin program: %w", err)
if err := pin(p.pinnedPath, fileName, p.fd); err != nil {
return err
}
p.pinnedPath = fileName
return nil
}

// Unpin removes the persisted state for the Program from the BPF virtual filesystem.
//
// Failed calls to Unpin will not alter the state returned by IsPinned.
//
// Unpinning an unpinned Program returns nil.
func (p *Program) Unpin() error {
if err := unpin(p.pinnedPath); err != nil {
return err
}
p.pinnedPath = ""
return nil
}

// IsPinned returns true if the Program has a non-empty pinned path.
func (p *Program) IsPinned() bool {
if p.pinnedPath == "" {
return false
}
return true
}

// Close unloads the program from the kernel.
func (p *Program) Close() error {
if p == nil {
Expand Down Expand Up @@ -585,7 +609,7 @@ func LoadPinnedProgram(fileName string) (*Program, error) {
return nil, fmt.Errorf("info for %s: %w", fileName, err)
}

return &Program{"", fd, filepath.Base(fileName), info.Type}, nil
return &Program{"", fd, filepath.Base(fileName), "", info.Type}, nil
}

// SanitizeName replaces all invalid characters in name with replacement.
Expand Down
31 changes: 31 additions & 0 deletions prog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ import (
"errors"
"fmt"
"math"
"os"
"path/filepath"
"runtime"
"strings"
"syscall"
"testing"
"time"

qt "github.com/frankban/quicktest"

"github.com/cilium/ebpf/asm"
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/testutils"
Expand Down Expand Up @@ -180,6 +183,7 @@ func TestProgramClose(t *testing.T) {

func TestProgramPin(t *testing.T) {
prog := createSocketFilter(t)
c := qt.New(t)
defer prog.Close()

tmp := tempBPFFS(t)
Expand All @@ -188,6 +192,10 @@ func TestProgramPin(t *testing.T) {
if err := prog.Pin(path); err != nil {
t.Fatal(err)
}

pinned := prog.IsPinned()
c.Assert(pinned, qt.Equals, true)

prog.Close()

prog, err := LoadPinnedProgram(path)
Expand All @@ -202,6 +210,29 @@ func TestProgramPin(t *testing.T) {
}
}

func TestProgramUnpin(t *testing.T) {
prog := createSocketFilter(t)
c := qt.New(t)
defer prog.Close()

tmp := tempBPFFS(t)

path := filepath.Join(tmp, "program")
if err := prog.Pin(path); err != nil {
t.Fatal(err)
}

pinned := prog.IsPinned()
c.Assert(pinned, qt.Equals, true)

if err := prog.Unpin(); err != nil {
t.Fatal("Failed to unpin program:", err)
}
if _, err := os.Stat(path); err == nil {
t.Fatal("Pinned program path still exists after unpinning:", err)
}
}

func TestProgramVerifierOutputOnError(t *testing.T) {
_, err := NewProgram(&ProgramSpec{
Type: SocketFilter,
Expand Down

0 comments on commit 32458a7

Please sign in to comment.