-
Notifications
You must be signed in to change notification settings - Fork 392
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
tetragon: Add map ownership #2945
Changes from all commits
05ffe97
c8d476d
30bf4cc
14877c0
7822f97
3d639d5
47b5d10
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
/* Copyright Authors of Cilium */ | ||
|
||
#include "vmlinux.h" | ||
#include "api.h" | ||
#include "bpf_tracing.h" | ||
#include "bpf_helpers.h" | ||
#include "compiler.h" | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_HASH); | ||
__uint(max_entries, 1); | ||
__type(key, int); | ||
__type(value, unsigned long); | ||
} m1 SEC(".maps"); | ||
|
||
__attribute__((section("kprobe/wake_up_new_task"), used)) int | ||
BPF_KPROBE(p2) | ||
{ | ||
map_lookup_elem(&m1, &(unsigned long){ 0 }); | ||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,17 @@ | |
// - map is local for program, not shared at all | ||
// | ||
// NOTE Please do not share MapTypeProgram maps, it brings confusion. | ||
// | ||
// Each map declares the ownership of the map. The map can be either | ||
// owner of the map (via MapBuilder* helpers) or as an user (MapUser* | ||
// helpers. | ||
// | ||
// Map owner object owns the pinned map and when loading it sets (and | ||
// potentially overwrite) the map's spec and its max entries value. | ||
// | ||
// Map user object object is just using the pinned map and follows its | ||
// setup and will fail if the pinned map differs in spec or configured | ||
// max entries value. | ||
|
||
package program | ||
|
||
|
@@ -75,6 +86,11 @@ const ( | |
MapTypeProgram | ||
) | ||
|
||
type MapOpts struct { | ||
Type MapType | ||
Owner bool | ||
} | ||
|
||
// Map represents BPF maps. | ||
type Map struct { | ||
Name string | ||
|
@@ -85,6 +101,7 @@ type Map struct { | |
Entries MaxEntries | ||
InnerEntries MaxEntries | ||
Type MapType | ||
Owner bool | ||
} | ||
|
||
// Map holds pointer to Program object as a source of its ebpf object | ||
|
@@ -100,40 +117,64 @@ type Map struct { | |
// p.PinMap["map2"] = &map2 | ||
// ... | ||
// p.PinMap["mapX"] = &mapX | ||
func mapBuilder(name string, ty MapType, lds ...*Program) *Map { | ||
m := &Map{name, "", lds[0], Idle(), nil, MaxEntries{0, false}, MaxEntries{0, false}, ty} | ||
func mapBuilder(name string, ty MapType, owner bool, lds ...*Program) *Map { | ||
m := &Map{name, "", lds[0], Idle(), nil, MaxEntries{0, false}, MaxEntries{0, false}, ty, owner} | ||
for _, ld := range lds { | ||
ld.PinMap[name] = m | ||
} | ||
return m | ||
} | ||
|
||
func MapBuilder(name string, lds ...*Program) *Map { | ||
return mapBuilder(name, MapTypeGlobal, lds...) | ||
return mapBuilder(name, MapTypeGlobal, true, lds...) | ||
} | ||
|
||
func MapBuilderProgram(name string, lds ...*Program) *Map { | ||
return mapBuilder(name, MapTypeProgram, lds...) | ||
return mapBuilder(name, MapTypeProgram, true, lds...) | ||
} | ||
|
||
func MapBuilderSensor(name string, lds ...*Program) *Map { | ||
return mapBuilder(name, MapTypeSensor, lds...) | ||
return mapBuilder(name, MapTypeSensor, true, lds...) | ||
} | ||
|
||
func MapBuilderPolicy(name string, lds ...*Program) *Map { | ||
return mapBuilder(name, MapTypePolicy, lds...) | ||
return mapBuilder(name, MapTypePolicy, true, lds...) | ||
} | ||
|
||
func MapBuilderType(name string, ty MapType, lds ...*Program) *Map { | ||
return mapBuilder(name, ty, lds...) | ||
return mapBuilder(name, ty, true, lds...) | ||
} | ||
|
||
func MapBuilderOpts(name string, opts MapOpts, lds ...*Program) *Map { | ||
return mapBuilder(name, opts.Type, opts.Owner, lds...) | ||
} | ||
|
||
func MapUser(name string, lds ...*Program) *Map { | ||
return mapBuilder(name, MapTypeGlobal, false, lds...) | ||
} | ||
|
||
func MapUserProgram(name string, lds ...*Program) *Map { | ||
return mapBuilder(name, MapTypeProgram, false, lds...) | ||
} | ||
|
||
func MapUserSensor(name string, lds ...*Program) *Map { | ||
return mapBuilder(name, MapTypeSensor, false, lds...) | ||
} | ||
|
||
func MapUserPolicy(name string, lds ...*Program) *Map { | ||
return mapBuilder(name, MapTypePolicy, false, lds...) | ||
} | ||
|
||
func PolicyMapPath(mapDir, policy, name string) string { | ||
return filepath.Join(mapDir, policy, name) | ||
} | ||
|
||
func (m *Map) IsOwner() bool { | ||
return m.Owner | ||
} | ||
|
||
func (m *Map) Unload() error { | ||
log := logger.GetLogger().WithField("map", m.Name).WithField("pin", m.Name) | ||
log := logger.GetLogger().WithField("map", m.Name).WithField("pin", m.PinPath) | ||
if !m.PinState.IsLoaded() { | ||
log.WithField("count", m.PinState.count).Debug("Refusing to unload map as it is not loaded") | ||
return nil | ||
|
@@ -216,7 +257,7 @@ func (m *Map) LoadOrCreatePinnedMap(pinPath string, mapSpec *ebpf.MapSpec) error | |
m.MapHandle.Close() | ||
} | ||
|
||
mh, err := LoadOrCreatePinnedMap(pinPath, mapSpec) | ||
mh, err := LoadOrCreatePinnedMap(pinPath, mapSpec, m.IsOwner()) | ||
if err != nil { | ||
return err | ||
} | ||
|
@@ -231,11 +272,12 @@ func isValidSubdir(d string) bool { | |
return dir != "." && dir != ".." | ||
} | ||
|
||
func LoadOrCreatePinnedMap(pinPath string, mapSpec *ebpf.MapSpec) (*ebpf.Map, error) { | ||
func LoadOrCreatePinnedMap(pinPath string, mapSpec *ebpf.MapSpec, create bool) (*ebpf.Map, error) { | ||
var err error | ||
// Try to open the pinPath and if it exist use the previously | ||
// pinned map otherwise pin the map and next user will find | ||
// it here. | ||
if _, err := os.Stat(pinPath); err == nil { | ||
if _, err = os.Stat(pinPath); err == nil { | ||
m, err := ebpf.LoadPinnedMap(pinPath, nil) | ||
if err != nil { | ||
return nil, fmt.Errorf("loading pinned map from path '%s' failed: %w", pinPath, err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it make sense to re-create here if we have create true? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hm, so this leg is when there is already an existing pin and we check if the pin is compatible with what we want to create, if it is, we are done, if not, we remove the pin and create new one |
||
|
@@ -244,14 +286,27 @@ func LoadOrCreatePinnedMap(pinPath string, mapSpec *ebpf.MapSpec) (*ebpf.Map, er | |
logger.GetLogger().WithError(err).WithFields(logrus.Fields{ | ||
"path": pinPath, | ||
"map-name": mapSpec.Name, | ||
}).Warn("tetragon, incompatible map found: will delete and recreate") | ||
}).Warn("incompatible map found") | ||
m.Close() | ||
os.Remove(pinPath) | ||
} else { | ||
return m, nil | ||
// If we are creating the map, let's ignore the compatibility error, | ||
// remove the pin and create the map with our spec. | ||
if create { | ||
logger.GetLogger().WithField("map", mapSpec.Name). | ||
Warn("will delete and recreate") | ||
os.Remove(pinPath) | ||
return createPinnedMap(pinPath, mapSpec) | ||
} | ||
return nil, fmt.Errorf("incompatible map '%s'", pinPath) | ||
} | ||
return m, nil | ||
} | ||
if create { | ||
return createPinnedMap(pinPath, mapSpec) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could move this create just after the state(pinPath) failure , and have the rest outside of if , just for readability up to you There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hm, so it is already in the place after the stat failure.. not sure what you mean |
||
} | ||
return nil, err | ||
} | ||
|
||
func createPinnedMap(pinPath string, mapSpec *ebpf.MapSpec) (*ebpf.Map, error) { | ||
// check if PinName has directory portion and create it, | ||
// filepath.Dir returns '.' for filename without dir portion | ||
if dir := filepath.Dir(pinPath); isValidSubdir(dir) { | ||
|
@@ -274,6 +329,15 @@ func LoadOrCreatePinnedMap(pinPath string, mapSpec *ebpf.MapSpec) (*ebpf.Map, er | |
return m, nil | ||
} | ||
|
||
func GetMaxEntriesPinnedMap(pinPath string) (uint32, error) { | ||
m, err := ebpf.LoadPinnedMap(pinPath, nil) | ||
if err != nil { | ||
return 0, fmt.Errorf("loading pinned map from path '%s' failed: %w", pinPath, err) | ||
} | ||
defer m.Close() | ||
return m.MaxEntries(), nil | ||
} | ||
|
||
func (m *Map) SetMaxEntries(max int) { | ||
m.Entries = MaxEntries{uint32(max), true} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding the comments!