Skip to content

Commit

Permalink
wip symbol API
Browse files Browse the repository at this point in the history
Signed-off-by: Simone Magnani <[email protected]>
  • Loading branch information
smagnani96 committed Sep 4, 2024
1 parent f1cefad commit 5137cbe
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 12 deletions.
17 changes: 17 additions & 0 deletions cmd/bpf2go/gen/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ func (n templateName) MapSpecs() string {
return string(n) + "MapSpecs"
}

func (n templateName) VariableSpecs() string {
return string(n) + "VariableSpecs"
}

func (n templateName) Load() string {
return n.maybeExport("load" + toUpperFirst(string(n)))
}
Expand All @@ -65,6 +69,10 @@ func (n templateName) Maps() string {
return string(n) + "Maps"
}

func (n templateName) Variables() string {
return string(n) + "Variables"
}

func (n templateName) Programs() string {
return string(n) + "Programs"
}
Expand All @@ -82,6 +90,8 @@ type GenerateArgs struct {
Constraints constraint.Expr
// Maps to be emitted.
Maps []string
// Variables to be emitted.
Variables []string
// Programs to be emitted.
Programs []string
// Types to be emitted.
Expand Down Expand Up @@ -116,6 +126,11 @@ func Generate(args GenerateArgs) error {
maps[name] = internal.Identifier(name)
}

vars := make(map[string]string)
for _, name := range args.Variables {
vars[name] = internal.Identifier(name)
}

programs := make(map[string]string)
for _, name := range args.Programs {
programs[name] = internal.Identifier(name)
Expand Down Expand Up @@ -146,6 +161,7 @@ func Generate(args GenerateArgs) error {
Constraints constraint.Expr
Name templateName
Maps map[string]string
Variables map[string]string
Programs map[string]string
Types []btf.Type
TypeNames map[btf.Type]string
Expand All @@ -157,6 +173,7 @@ func Generate(args GenerateArgs) error {
args.Constraints,
templateName(args.Stem),
maps,
vars,
programs,
types,
typeNames,
Expand Down
29 changes: 29 additions & 0 deletions cmd/bpf2go/gen/output.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func {{ .Name.LoadObjects }}(obj interface{}, opts *ebpf.CollectionOptions) (err
type {{ .Name.Specs }} struct {
{{ .Name.ProgramSpecs }}
{{ .Name.MapSpecs }}
{{ .Name.VariableSpecs }}
}

// {{ .Name.Specs }} contains programs before they are loaded into the kernel.
Expand All @@ -80,12 +81,14 @@ type {{ .Name.MapSpecs }} struct {
type {{ .Name.Objects }} struct {
{{ .Name.Programs }}
{{ .Name.Maps }}
{{ .Name.Variables }}
}

func (o *{{ .Name.Objects }}) Close() error {
return {{ .Name.CloseHelper }}(
&o.{{ .Name.Programs }},
&o.{{ .Name.Maps }},
&o.{{ .Name.Variables }},
)
}

Expand All @@ -106,6 +109,32 @@ func (m *{{ .Name.Maps }}) Close() error {
)
}

// {{ .Name.VariableSpecs }} contains variables before they are loaded into the kernel.
//
// It can be passed ebpf.CollectionSpec.Assign.
type {{ .Name.VariableSpecs }} struct {
{{- range $name, $id := .Variables }}
{{ $id }} *ebpf.VariableSpec `ebpf:"{{ $name }}"`
{{- end }}
}

// {{ .Name.Variables }} contains all variables after they have been loaded into the kernel.
//
// It can be passed to {{ .Name.LoadObjects }} or ebpf.CollectionSpec.LoadAndAssign.
type {{ .Name.Variables }} struct {
{{- range $name, $id := .Variables }}
{{ $id }} *ebpf.Variable `ebpf:"{{ $name }}"`
{{- end }}
}

func (m *{{ .Name.Variables }}) Close() error {
return {{ .Name.CloseHelper }}(
{{- range $id := .Variables }}
m.{{ $id }},
{{- end }}
)
}

// {{ .Name.Programs }} contains all programs after they have been loaded into the kernel.
//
// It can be passed to {{ .Name.LoadObjects }} or ebpf.CollectionSpec.LoadAndAssign.
Expand Down
6 changes: 6 additions & 0 deletions cmd/bpf2go/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,11 @@ func (b2g *bpf2go) convert(tgt gen.Target, goarches gen.GoArches) (err error) {
}
}

var vars []string
for name := range spec.Variables {
vars = append(vars, name)
}

var programs []string
for name := range spec.Programs {
programs = append(programs, name)
Expand Down Expand Up @@ -397,6 +402,7 @@ func (b2g *bpf2go) convert(tgt gen.Target, goarches gen.GoArches) (err error) {
Stem: b2g.identStem,
Constraints: constraints,
Maps: maps,
Variables: vars,
Programs: programs,
Types: types,
ObjectFile: filepath.Base(objFileName),
Expand Down
91 changes: 80 additions & 11 deletions collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ import (
//
// Maps and Programs are passed to NewMapWithOptions and NewProgramsWithOptions.
type CollectionOptions struct {
Maps MapOptions
Programs ProgramOptions
Maps MapOptions
Variables VariableOptions
Programs ProgramOptions

// MapReplacements takes a set of Maps that will be used instead of
// creating new ones when loading the CollectionSpec.
Expand All @@ -36,8 +37,9 @@ type CollectionOptions struct {

// CollectionSpec describes a collection.
type CollectionSpec struct {
Maps map[string]*MapSpec
Programs map[string]*ProgramSpec
Maps map[string]*MapSpec
Variables map[string]*VariableSpec
Programs map[string]*ProgramSpec

// Types holds type information about Maps and Programs.
// Modifications to Types are currently undefined behaviour.
Expand All @@ -56,6 +58,7 @@ func (cs *CollectionSpec) Copy() *CollectionSpec {

cpy := CollectionSpec{
Maps: make(map[string]*MapSpec, len(cs.Maps)),
Variables: make(map[string]*VariableSpec, len(cs.Variables)),
Programs: make(map[string]*ProgramSpec, len(cs.Programs)),
ByteOrder: cs.ByteOrder,
Types: cs.Types.Copy(),
Expand All @@ -65,6 +68,10 @@ func (cs *CollectionSpec) Copy() *CollectionSpec {
cpy.Maps[name] = spec.Copy()
}

for name, spec := range cs.Variables {
cpy.Variables[name] = spec.Copy()
}

for name, spec := range cs.Programs {
cpy.Programs[name] = spec.Copy()
}
Expand Down Expand Up @@ -286,6 +293,7 @@ func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions)

// Support assigning Programs and Maps, lazy-loading the required objects.
assignedMaps := make(map[string]bool)
assignedVars := make(map[string]bool)
assignedProgs := make(map[string]bool)

getValue := func(typ reflect.Type, name string) (interface{}, error) {
Expand All @@ -299,6 +307,10 @@ func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions)
assignedMaps[name] = true
return loader.loadMap(name)

case reflect.TypeOf((*Variable)(nil)):
assignedVars[name] = true
return loader.loadVariable(name)

default:
return nil, fmt.Errorf("unsupported type %s", typ)
}
Expand Down Expand Up @@ -336,18 +348,21 @@ func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions)
for m := range assignedMaps {
delete(loader.maps, m)
}
for v := range assignedVars {
delete(loader.vars, v)
}
for p := range assignedProgs {
delete(loader.programs, p)
}

return nil
}

// Collection is a collection of Programs and Maps associated
// with their symbols
// Collection is a collection of Programs and Maps associated with their variables
type Collection struct {
Programs map[string]*Program
Maps map[string]*Map
Programs map[string]*Program
Maps map[string]*Map
Variables map[string]*Variable
}

// NewCollection creates a Collection from the given spec, creating and
Expand Down Expand Up @@ -377,6 +392,11 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Co
return nil, err
}
}
for varName := range spec.Variables {
if _, err := loader.loadVariable(varName); err != nil {
return nil, err
}
}

for progName, prog := range spec.Programs {
if prog.Type == UnspecifiedProgram {
Expand All @@ -394,20 +414,23 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Co
return nil, err
}

// Prevent loader.cleanup from closing maps and programs.
maps, progs := loader.maps, loader.programs
loader.maps, loader.programs = nil, nil
// Prevent loader.cleanup from closing maps, vars and programs.
maps, vars, progs := loader.maps, loader.vars, loader.programs
loader.maps, loader.vars, loader.programs = nil, nil, nil

return &Collection{
progs,
maps,
vars,
}, nil
}

type collectionLoader struct {
coll *CollectionSpec
opts *CollectionOptions
maps map[string]*Map
vars map[string]*Variable
memory map[string]*MapMemory
programs map[string]*Program
}

Expand All @@ -432,6 +455,8 @@ func newCollectionLoader(coll *CollectionSpec, opts *CollectionOptions) (*collec
coll,
opts,
make(map[string]*Map),
make(map[string]*Variable),
make(map[string]*MapMemory),
make(map[string]*Program),
}, nil
}
Expand All @@ -446,6 +471,39 @@ func (cl *collectionLoader) close() {
}
}

func (cl *collectionLoader) loadVariable(varName string) (*Variable, error) {
if s := cl.vars[varName]; s != nil {
return s, nil
}

varSpec := cl.coll.Variables[varName]
if varSpec == nil {
return nil, fmt.Errorf("missing variable %s", varName)
}

m := cl.maps[varSpec.MapName]
if m == nil {
return nil, fmt.Errorf("map %s for variable %s not found", varSpec.MapName, varName)
}

if _, ok := cl.memory[varSpec.MapName]; !ok {
// TODO: kernel before mmap support will always fail to load a prog with variables
mm, err := m.Memory()
if err != nil {
return nil, err
}
cl.memory[varSpec.MapName] = mm
}

v, err := newVariableWithOptions(varSpec, cl.memory[varSpec.MapName], cl.opts.Variables)
if err != nil {
return nil, fmt.Errorf("variable %v: %w", varName, err)
}

cl.vars[varName] = v
return v, nil
}

func (cl *collectionLoader) loadMap(mapName string) (*Map, error) {
if m := cl.maps[mapName]; m != nil {
return m, nil
Expand Down Expand Up @@ -723,6 +781,7 @@ func LoadCollection(file string) (*Collection, error) {
// for any successful assigns. On error `to` is left in an undefined state.
func (coll *Collection) Assign(to interface{}) error {
assignedMaps := make(map[string]bool)
assignedVars := make(map[string]bool)
assignedProgs := make(map[string]bool)

// Assign() only transfers already-loaded Maps and Programs. No extra
Expand All @@ -744,6 +803,13 @@ func (coll *Collection) Assign(to interface{}) error {
}
return nil, fmt.Errorf("missing map %q", name)

case reflect.TypeOf((*Variable)(nil)):
if v := coll.Variables[name]; v != nil {
assignedVars[name] = true
return v, nil
}
return nil, fmt.Errorf("missing variable %q", name)

default:
return nil, fmt.Errorf("unsupported type %s", typ)
}
Expand All @@ -757,6 +823,9 @@ func (coll *Collection) Assign(to interface{}) error {
for p := range assignedProgs {
delete(coll.Programs, p)
}
for s := range assignedVars {
delete(coll.Variables, s)
}
for m := range assignedMaps {
delete(coll.Maps, m)
}
Expand Down
8 changes: 8 additions & 0 deletions collection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ func TestCollectionSpecCopy(t *testing.T) {
MaxEntries: 1,
},
},
map[string]*VariableSpec{
"test": {
Name: "test",
MapName: ".rodata",
Offset: 0,
Size: 4,
},
},
map[string]*ProgramSpec{
"test": {
Type: SocketFilter,
Expand Down
Loading

0 comments on commit 5137cbe

Please sign in to comment.