Skip to content

Commit

Permalink
pkg/sensors: exclude shared maps memory use on policies
Browse files Browse the repository at this point in the history
Avoid to double count for shared maps, like the execve_maps for example.

I decided to make it dynamic by reading the global BPF fs directory,
this might use too much CPU since we should be aware of what are the
current global maps since we load them ourselves, so it could be
optimized if it's too heavy:
* naively by hardcoding some of the shared maps by names
* smartly by hooking the loading of global maps

Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
  • Loading branch information
mtardy committed Oct 8, 2024
1 parent 5e6ce8e commit 1243fc4
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 5 deletions.
5 changes: 3 additions & 2 deletions cmd/tetra/debug/maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"text/tabwriter"

"github.com/cilium/tetragon/pkg/bpf"
"github.com/cilium/tetragon/pkg/bugtool"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -46,7 +47,7 @@ many maps were aggregated for the given name. It ranks map from the one
consuming the most memory to the one consuming the less. Use the -n flag to
adjust the number of item in the table.
[^1]: https://lore.kernel.org/all/20230305124615.12358-1-laoar.shao@gmail.com/`, bugtool.TetragonBPFFS),
[^1]: https://lore.kernel.org/all/20230305124615.12358-1-laoar.shao@gmail.com/`, bpf.TetragonBPFFS),
RunE: func(cmd *cobra.Command, _ []string) error {
if output != "tab" && output != "json" {
return fmt.Errorf("invalid output format %q, please use one of tab or json", output)
Expand Down Expand Up @@ -142,7 +143,7 @@ adjust the number of item in the table.
flags := cmd.Flags()
flags.IntVarP(&lines, "lines", "n", 10, "Number of lines for the top BPF map memory consumers.\nUse 0 to print all lines. Only valid with tab output.")
flags.StringVarP(&output, "output", "o", "tab", "Output format. One of tab or json.")
flags.StringVar(&path, "path", bugtool.TetragonBPFFS, "Path of the BPF filesystem.")
flags.StringVar(&path, "path", bpf.TetragonBPFFS, "Path of the BPF filesystem.")

return &cmd
}
36 changes: 36 additions & 0 deletions pkg/bpf/maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ import (
"fmt"
"io"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/cilium/ebpf"
)

const TetragonBPFFS = "/sys/fs/bpf/tetragon"

type ExtendedMapInfo struct {
ebpf.MapInfo
Memlock int
Expand Down Expand Up @@ -98,3 +101,36 @@ func parseMemlockFromFDInfoReader(r io.Reader) (int, error) {
}
return 0, fmt.Errorf("didn't find memlock field")
}

// GlobalMapsIDs returns the IDs of the global maps under /sys/fs/bpf/tetragon.
// There might be a better way to always known which global maps are loaded
// without reading from the folder again.
func GlobalMapsIDs() (map[ebpf.MapID]bool, error) {
entries, err := os.ReadDir(TetragonBPFFS)
if err != nil {
return nil, fmt.Errorf("failed to read the directory %s: %w", TetragonBPFFS, err)
}
globalMapsIDs := map[ebpf.MapID]bool{}
for _, entry := range entries {
if !entry.IsDir() {
m, err := ebpf.LoadPinnedMap(filepath.Join(TetragonBPFFS, entry.Name()), &ebpf.LoadPinOptions{
ReadOnly: true,
})
if err != nil {
return nil, fmt.Errorf("failed to open map %s: %w", filepath.Join(TetragonBPFFS, entry.Name()), err)
}
defer m.Close()
info, err := m.Info()
if err != nil {
return nil, fmt.Errorf("failed to retrieve info: %w", err)
}
id, available := info.ID()
if !available {
return nil, fmt.Errorf("failed to retrieve the IDs, kernel might be <4.13")
}
globalMapsIDs[id] = true
}
}

return globalMapsIDs, nil
}
3 changes: 2 additions & 1 deletion pkg/bugtool/bugtool.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (

"github.com/cilium/tetragon/api/v1/tetragon"
"github.com/cilium/tetragon/cmd/tetra/common"
"github.com/cilium/tetragon/pkg/bpf"
"github.com/cilium/tetragon/pkg/defaults"
"github.com/cilium/tetragon/pkg/logger"
"github.com/cilium/tetragon/pkg/policyfilter"
Expand Down Expand Up @@ -758,7 +759,7 @@ func (s bugtoolInfo) addMemCgroupStats(tarWriter *tar.Writer) error {
}

func (s bugtoolInfo) addBPFMapsStats(tarWriter *tar.Writer) error {
out, err := RunMapsChecks(TetragonBPFFS)
out, err := RunMapsChecks(bpf.TetragonBPFFS)
if err != nil {
s.multiLog.WithError(err).Warn("failed to run BPF maps checks")
return fmt.Errorf("failed to run BPF maps checks: %w", err)
Expand Down
2 changes: 0 additions & 2 deletions pkg/bugtool/maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,6 @@ func isBPFObject(object string, fd int) (bool, error) {
return readlink == fmt.Sprintf("anon_inode:bpf-%s", object), nil
}

const TetragonBPFFS = "/sys/fs/bpf/tetragon"

type DiffMap struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Expand Down
11 changes: 11 additions & 0 deletions pkg/sensors/sensors.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ func (s *Sensor) IsLoaded() bool {
}

func (s Sensor) TotalMemlock() int {
sharedMapsIDs, err := bpf.GlobalMapsIDs()
if err != nil {
logger.GetLogger().WithError(err).Warn("failed to list global maps IDs, byte usage of maps by sensor might be overestimated")
}

uniqueMap := map[int]bpf.ExtendedMapInfo{}
for _, p := range s.Progs {
for id, info := range p.LoadedMapsInfo {
Expand All @@ -101,8 +106,14 @@ func (s Sensor) TotalMemlock() int {

var total int
for _, info := range uniqueMap {
id, available := info.ID()
if available && sharedMapsIDs[id] {
// best effort, the ID might be missing for <4.13
continue
}
total += info.Memlock
}

return total
}

Expand Down

0 comments on commit 1243fc4

Please sign in to comment.