Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/bpf2go: enable building custom tools (wip) #1320

Closed
wants to merge 1 commit into from
Closed
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
8 changes: 4 additions & 4 deletions cmd/bpf2go/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type compileArgs struct {
dep io.Writer
}

func compile(args compileArgs) error {
func compile(args compileArgs, tc TargetCustomisations) error {
// Default cflags that can be overridden by args.cFlags
overrideFlags := []string{
// Code needs to be optimized, otherwise the verifier will often fail
Expand Down Expand Up @@ -90,7 +90,7 @@ func compile(args compileArgs) error {
)
}

if err := cmd.Run(); err != nil {
if err := tc.Compile(cmd); err != nil {
return fmt.Errorf("can't execute %s: %s", args.cc, err)
}

Expand Down Expand Up @@ -200,10 +200,10 @@ func parseDependencies(baseDir string, in io.Reader) ([]dependency, error) {
}

// strip DWARF debug info from file by executing exe.
func strip(exe, file string) error {
func strip(exe, file string, tc TargetCustomisations) error {
cmd := exec.Command(exe, "-g", file)
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
if err := tc.Strip(cmd); err != nil {
return fmt.Errorf("%s: %s", exe, err)
}
return nil
Expand Down
8 changes: 4 additions & 4 deletions cmd/bpf2go/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestCompile(t *testing.T) {
source: filepath.Join(dir, "test.c"),
dest: filepath.Join(dir, "test.o"),
dep: &dep,
})
}, &CustomisationsBase{})
if err != nil {
t.Fatal("Can't compile:", err)
}
Expand Down Expand Up @@ -55,7 +55,7 @@ func TestReproducibleCompile(t *testing.T) {
dir: dir,
source: filepath.Join(dir, "test.c"),
dest: filepath.Join(dir, "a.o"),
})
}, &CustomisationsBase{})
if err != nil {
t.Fatal("Can't compile:", err)
}
Expand All @@ -65,7 +65,7 @@ func TestReproducibleCompile(t *testing.T) {
dir: dir,
source: filepath.Join(dir, "test.c"),
dest: filepath.Join(dir, "b.o"),
})
}, &CustomisationsBase{})
if err != nil {
t.Fatal("Can't compile:", err)
}
Expand Down Expand Up @@ -94,7 +94,7 @@ func TestTriggerMissingTarget(t *testing.T) {
dir: dir,
source: filepath.Join(dir, "test.c"),
dest: filepath.Join(dir, "a.o"),
})
}, &CustomisationsBase{})

if err == nil {
t.Fatal("No error when compiling __BPF_TARGET_MISSING")
Expand Down
67 changes: 67 additions & 0 deletions cmd/bpf2go/customisations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package main

import (
"flag"
"io"
"os/exec"

"github.com/cilium/ebpf"
)

// Run implements bpf2go tool; leverage bpf2go and build custom tools on
// top by providing Customisations
func Run(stdout io.Writer, pkg, outputDir string, args []string, c Customisations) (err error) {
return run(stdout, pkg, outputDir, args, c)
}

// Customisations enables building custom tools on top of bpf2go
type Customisations interface {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drive-by nit: isn't this basically a variation of *Options, but with an interface instead of a struct?

// ModifyFlags adds custom tool's own flags
ModifyFlags(*flag.FlagSet)

// NewTarget provides decdicated TargetCustomisations per target; a
// custom tool implements further customisations via
// TargetCustomisations (can contain target-specific state)
NewTarget(target) TargetCustomisations
}

// TargetCustomisations enables building custom tools on top of bpf2go
type TargetCustomisations interface {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference with a Customizations? Why are they split?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are split to enable storing target-specific state in TargetCustomisations. E.g. read DWARF in .Compile, later use the data in .AugmentSpec.

// Compile compiles C source code; instead of running the provided
// command as is, a custom tool could do something more exciting,
// such as transparently running compiler in a Docker container or
// implement a cache, or even run a custom preprocessor to have
// e.g. golang package-aware includes
Compile(*exec.Cmd) error

// Strip strips the object file; instead of running the provided
// command as is, a custom tool could do something more exciting
// such as transparently running strip in a Docker container or
// implement a cache
Strip(*exec.Cmd) error

// AugmentSpec optionally adds to the spec; e.g. a custom tool could
// add types from DWARF debug info so that the tool could generate
// golang type even when C type is not included in BTF
AugmentSpec(*ebpf.CollectionSpec) error
}

// CustomisationsBase is a baseline implementation of Cusomisations,
// TargetCustomisations
type CustomisationsBase struct{}

func (cb *CustomisationsBase) ModifyFlags(fs *flag.FlagSet) {}

func (cb *CustomisationsBase) NewTarget(target) TargetCustomisations { return cb }

func (cb *CustomisationsBase) Compile(cmd *exec.Cmd) error {
return cmd.Run()
}

func (cb *CustomisationsBase) Strip(cmd *exec.Cmd) error {
return cmd.Run()
}

func (cb *CustomisationsBase) AugmentSpec(*ebpf.CollectionSpec) error {
return nil
}
24 changes: 18 additions & 6 deletions cmd/bpf2go/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ var targetByGoArch = map[goarch]target{
"s390x": {"bpfeb", "s390"},
}

func run(stdout io.Writer, pkg, outputDir string, args []string) (err error) {
b2g, err := newB2G(stdout, pkg, outputDir, args)
func run(stdout io.Writer, pkg, outputDir string, args []string, c Customisations) (err error) {
b2g, err := newB2G(stdout, pkg, outputDir, args, c)
switch {
case err == nil:
return b2g.convertAll()
Expand Down Expand Up @@ -109,13 +109,17 @@ type bpf2go struct {
// Base directory of the Makefile. Enables outputting make-style dependencies
// in .d files.
makeBase string

customisations Customisations
}

func newB2G(stdout io.Writer, pkg, outputDir string, args []string) (*bpf2go, error) {
func newB2G(stdout io.Writer, pkg, outputDir string, args []string, c Customisations) (*bpf2go, error) {
b2g := &bpf2go{
stdout: stdout,
pkg: pkg,
outputDir: outputDir,

customisations: c,
}

fs := flag.NewFlagSet("bpf2go", flag.ContinueOnError)
Expand All @@ -141,6 +145,7 @@ func newB2G(stdout io.Writer, pkg, outputDir string, args []string) (*bpf2go, er
fmt.Fprintln(fs.Output())
printTargets(fs.Output())
}
c.ModifyFlags(fs)
if err := fs.Parse(args); err != nil {
return nil, err
}
Expand Down Expand Up @@ -345,6 +350,8 @@ func (b2g *bpf2go) convert(tgt target, goarches []goarch) (err error) {
return fmt.Errorf("remove obsolete output: %w", err)
}

tc := b2g.customisations.NewTarget(tgt)

var dep bytes.Buffer
err = compile(compileArgs{
cc: b2g.cc,
Expand All @@ -354,15 +361,15 @@ func (b2g *bpf2go) convert(tgt target, goarches []goarch) (err error) {
source: b2g.sourceFile,
dest: objFileName,
dep: &dep,
})
}, tc)
if err != nil {
return err
}

fmt.Fprintln(b2g.stdout, "Compiled", objFileName)

if !b2g.disableStripping {
if err := strip(b2g.strip, objFileName); err != nil {
if err := strip(b2g.strip, objFileName, tc); err != nil {
return err
}
fmt.Fprintln(b2g.stdout, "Stripped", objFileName)
Expand All @@ -373,6 +380,11 @@ func (b2g *bpf2go) convert(tgt target, goarches []goarch) (err error) {
return fmt.Errorf("can't load BPF from ELF: %s", err)
}

err = tc.AugmentSpec(spec)
if err != nil {
return err
}

maps, programs, types, err := collectFromSpec(spec, b2g.cTypes, b2g.skipGlobalTypes)
if err != nil {
return err
Expand Down Expand Up @@ -533,7 +545,7 @@ func main() {
os.Exit(1)
}

if err := run(os.Stdout, os.Getenv(gopackageEnv), outputDir, os.Args[1:]); err != nil {
if err := run(os.Stdout, os.Getenv(gopackageEnv), outputDir, os.Args[1:], &CustomisationsBase{}); err != nil {
fmt.Fprintln(os.Stderr, "Error:", err)
os.Exit(1)
}
Expand Down
Loading
Loading