Skip to content

Commit

Permalink
pkg/sensors: reduce memory footprint of unused fdinstall maps
Browse files Browse the repository at this point in the history
Resize the fdinstall_map if needed to save memory, thus we are saving
~11MB of kernel memory by kprobe that are not using FollowFD, UnfollowFD
or CopyFD.

Signed-off-by: Mahe Tardy <[email protected]>
  • Loading branch information
mtardy committed Jun 14, 2024
1 parent 3c421d8 commit 6d462c0
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 7 deletions.
2 changes: 1 addition & 1 deletion bpf/process/types/basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -1777,7 +1777,7 @@ struct fdinstall_value {

struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(max_entries, 32000);
__uint(max_entries, 1); // will be resized by agent when needed
__type(key, struct fdinstall_key);
__type(value, struct fdinstall_value);
} fdinstall_map SEC(".maps");
Expand Down
63 changes: 57 additions & 6 deletions pkg/sensors/tracing/generickprobe.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const (
// much kernel memory when enabled.
stackTraceMapMaxEntries = 32768
ratelimitMapMaxEntries = 32768
fdInstallMapMaxEntries = 32000
)

func kprobeCharBufErrorToString(e int32) string {
Expand Down Expand Up @@ -144,6 +145,11 @@ type genericKprobe struct {
// is there ratelimit defined in the kprobe
hasRatelimit bool

// is the fdinstall feature used in the kprobe? This one should be uniform
// across all the kprobe from the same policy since the fdinstall map is
// shared between them
hasFDInstall bool

customHandler eventhandler.Handler
}

Expand Down Expand Up @@ -279,6 +285,7 @@ func createMultiKprobeSensor(sensorPath, policyName string, multiIDs []idtable.E
data := &genericKprobeData{}
oneKprobeHasStackTrace := false
oneKprobeHasRatelimit := false
resizeFDInstall := false

for _, id := range multiIDs {
gk, err := genericKprobeTableGet(id)
Expand All @@ -290,6 +297,10 @@ func createMultiKprobeSensor(sensorPath, policyName string, multiIDs []idtable.E
}
oneKprobeHasStackTrace = oneKprobeHasStackTrace || gk.hasStackTrace
oneKprobeHasRatelimit = oneKprobeHasRatelimit || gk.hasRatelimit
// it should be overkill (we could just get the value of the first)
// because the caller should have already uniformized hasFDInstall
// between all the kprobes
resizeFDInstall = resizeFDInstall || gk.hasFDInstall
gk.data = data
}

Expand All @@ -315,6 +326,9 @@ func createMultiKprobeSensor(sensorPath, policyName string, multiIDs []idtable.E
progs = append(progs, load)

fdinstall := program.MapBuilderPin("fdinstall_map", sensors.PathJoin(sensorPath, "fdinstall_map"), load)
if resizeFDInstall {
fdinstall.SetMaxEntries(fdInstallMapMaxEntries)
}
maps = append(maps, fdinstall)

configMap := program.MapBuilderPin("config_map", sensors.PathJoin(pinPath, "config_map"), load)
Expand Down Expand Up @@ -392,6 +406,9 @@ func createMultiKprobeSensor(sensorPath, policyName string, multiIDs []idtable.E
maps = append(maps, callHeap)

fdinstall := program.MapBuilderPin("fdinstall_map", sensors.PathJoin(sensorPath, "fdinstall_map"), loadret)
if resizeFDInstall {
fdinstall.SetMaxEntries(fdInstallMapMaxEntries)
}
maps = append(maps, fdinstall)

socktrack := program.MapBuilderPin("socktrack_map", sensors.PathJoin(sensorPath, "socktrack_map"), loadret)
Expand Down Expand Up @@ -529,6 +546,9 @@ type addKprobeIn struct {
policyID policyfilter.PolicyID
customHandler eventhandler.Handler
selMaps *selectors.KernelSelectorMaps
// if one of the kprobe in the policy need fdinstall, all of them needs to
// be created with resized fdinstall_map
oneKprobeHasFDInstall bool
}

func getKprobeSymbols(symbol string, syscall bool, lists []v1alpha1.ListSpec) ([]string, bool, error) {
Expand Down Expand Up @@ -578,13 +598,24 @@ func createGenericKprobeSensor(
selMaps = &selectors.KernelSelectorMaps{}
}

// detect at the policy level if one kprobe uses the fdinstall feature and
// then enable that in all of them in addKprobe
oneKprobeHasFDInstall := false
for _, kprobe := range kprobes {
if selectorsHaveFDInstall(kprobe.Selectors) {
oneKprobeHasFDInstall = true
break
}
}

in := addKprobeIn{
useMulti: useMulti,
sensorPath: name,
policyID: policyID,
policyName: policyName,
customHandler: customHandler,
selMaps: selMaps,
useMulti: useMulti,
sensorPath: name,
policyID: policyID,
policyName: policyName,
customHandler: customHandler,
selMaps: selMaps,
oneKprobeHasFDInstall: oneKprobeHasFDInstall,
}

for i := range kprobes {
Expand Down Expand Up @@ -801,6 +832,7 @@ func addKprobe(funcName string, f *v1alpha1.KProbeSpec, in *addKprobeIn) (id idt
tags: tagsField,
hasStackTrace: selectorsHaveStackTrace(f.Selectors),
hasRatelimit: selectorsHaveRateLimit(f.Selectors),
hasFDInstall: in.oneKprobeHasFDInstall,
}

// Parse Filters into kernel filter logic
Expand Down Expand Up @@ -863,6 +895,9 @@ func createKprobeSensorFromEntry(kprobeEntry *genericKprobe, sensorPath string,
progs = append(progs, load)

fdinstall := program.MapBuilderPin("fdinstall_map", sensors.PathJoin(sensorPath, "fdinstall_map"), load)
if kprobeEntry.hasFDInstall {
fdinstall.SetMaxEntries(fdInstallMapMaxEntries)
}
maps = append(maps, fdinstall)

configMap := program.MapBuilderPin("config_map", sensors.PathJoin(pinPath, "config_map"), load)
Expand Down Expand Up @@ -954,6 +989,9 @@ func createKprobeSensorFromEntry(kprobeEntry *genericKprobe, sensorPath string,
maps = append(maps, callHeap)

fdinstall := program.MapBuilderPin("fdinstall_map", sensors.PathJoin(sensorPath, "fdinstall_map"), loadret)
if kprobeEntry.hasFDInstall {
fdinstall.SetMaxEntries(fdInstallMapMaxEntries)
}
maps = append(maps, fdinstall)

if kernels.EnableLargeProgs() {
Expand Down Expand Up @@ -1316,3 +1354,16 @@ func selectorsHaveStackTrace(selectors []v1alpha1.KProbeSelector) bool {
}
return false
}

func selectorsHaveFDInstall(sel []v1alpha1.KProbeSelector) bool {
for _, selector := range sel {
for _, matchAction := range selector.MatchActions {
if a := selectors.ActionTypeFromString(matchAction.Action); a == selectors.ActionTypeFollowFd ||
a == selectors.ActionTypeUnfollowFd ||
a == selectors.ActionTypeCopyFd {
return true
}
}
}
return false
}
7 changes: 7 additions & 0 deletions pkg/sensors/tracing/generictracepoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ type genericTracepoint struct {

// custom event handler
customHandler eventhandler.Handler

// is the fdinstall feature used in the tracepoint
hasFDInstall bool
}

// genericTracepointArg is the internal representation of an output value of a
Expand Down Expand Up @@ -347,6 +350,7 @@ func createGenericTracepoint(
customHandler: customHandler,
message: msgField,
tags: tagsField,
hasFDInstall: selectorsHaveFDInstall(conf.Selectors),
}

genericTracepointTable.addTracepoint(ret)
Expand Down Expand Up @@ -405,6 +409,9 @@ func createGenericTracepointSensor(
progs = append(progs, prog0)

fdinstall := program.MapBuilderPin("fdinstall_map", sensors.PathJoin(pinPath, "fdinstall_map"), prog0)
if tp.hasFDInstall {
fdinstall.SetMaxEntries(fdInstallMapMaxEntries)
}
maps = append(maps, fdinstall)

tailCalls := program.MapBuilderPin("tp_calls", sensors.PathJoin(pinPath, "tp_calls"), prog0)
Expand Down

0 comments on commit 6d462c0

Please sign in to comment.