Skip to content

Commit

Permalink
tetragon: Add multi uprobe sensor
Browse files Browse the repository at this point in the history
Adding support to load multiple uprobes via uprobes multi interface.

Signed-off-by: Jiri Olsa <[email protected]>
  • Loading branch information
olsajiri committed Dec 26, 2023
1 parent 85349d6 commit 2dac95e
Showing 1 changed file with 126 additions and 11 deletions.
137 changes: 126 additions & 11 deletions pkg/sensors/tracing/genericuprobe.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/cilium/ebpf"
"github.com/cilium/tetragon/pkg/api/ops"
api "github.com/cilium/tetragon/pkg/api/tracingapi"
"github.com/cilium/tetragon/pkg/bpf"
"github.com/cilium/tetragon/pkg/grpc/tracing"
"github.com/cilium/tetragon/pkg/idtable"
"github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1"
Expand Down Expand Up @@ -96,14 +97,9 @@ func handleGenericUprobe(r *bytes.Reader) ([]observer.Event, error) {
return []observer.Event{unix}, err
}

func (k *observerUprobeSensor) LoadProbe(args sensors.LoadProbeArgs) error {
func loadSingleUprobeSensor(uprobeEntry *genericUprobe, args sensors.LoadProbeArgs) error {
load := args.Load

uprobeEntry, ok := load.LoaderData.(*genericUprobe)
if !ok {
return fmt.Errorf("invalid loadData type: expecting idtable.EntryID and got: %T (%v)", load.LoaderData, load.LoaderData)
}

// config_map data
var configData bytes.Buffer
binary.Write(&configData, binary.LittleEndian, uprobeEntry.config)
Expand Down Expand Up @@ -141,6 +137,80 @@ func (k *observerUprobeSensor) LoadProbe(args sensors.LoadProbeArgs) error {
return nil
}

func loadMultiUprobeSensor(ids []idtable.EntryID, args sensors.LoadProbeArgs) error {
load := args.Load
sensors.AllPrograms = append(sensors.AllPrograms, load)

data := &program.MultiUprobeAttachData{}
data.Attach = make(map[string]*program.MultiUprobeAttachSymbolsCookies)

for index, id := range ids {
uprobeEntry, err := genericUprobeTableGet(id)
if err != nil {
logger.GetLogger().WithError(err).Warnf("Failed to match id:%d", id)
return fmt.Errorf("Failed to match id")
}

// config_map data
var configData bytes.Buffer
binary.Write(&configData, binary.LittleEndian, uprobeEntry.config)

// filter_map data
selBuff := uprobeEntry.selectors.Buffer()

mapLoad := []*program.MapLoad{
{
Index: uint32(index),
Name: "config_map",
Load: func(m *ebpf.Map, index uint32) error {
return m.Update(index, configData.Bytes()[:], ebpf.UpdateAny)
},
},
{
Index: uint32(index),
Name: "filter_map",
Load: func(m *ebpf.Map, index uint32) error {
return m.Update(index, selBuff[:], ebpf.UpdateAny)
},
},
}
load.MapLoad = append(load.MapLoad, mapLoad...)

attach, ok := data.Attach[uprobeEntry.path]
if !ok {
attach = &program.MultiUprobeAttachSymbolsCookies{}
}

attach.Symbols = append(attach.Symbols, uprobeEntry.symbol)
attach.Cookies = append(attach.Cookies, uint64(index))

data.Attach[uprobeEntry.path] = attach
}

load.SetAttachData(data)

if err := program.LoadMultiUprobeProgram(args.BPFDir, args.MapDir, args.Load, args.Verbose); err == nil {
logger.GetLogger().Infof("Loaded generic kprobe sensor: %s -> %s", load.Name, load.Attach)
} else {
return err
}

return nil
}

func (k *observerUprobeSensor) LoadProbe(args sensors.LoadProbeArgs) error {
load := args.Load

if entry, ok := load.LoaderData.(*genericUprobe); ok {
return loadSingleUprobeSensor(entry, args)
}
if ids, ok := load.LoaderData.([]idtable.EntryID); ok {
return loadMultiUprobeSensor(ids, args)
}
return fmt.Errorf("invalid loadData type: expecting idtable.EntryID/[] and got: %T (%v)",
load.LoaderData, load.LoaderData)
}

func isValidUprobeSelectors(selectors []v1alpha1.KProbeSelector) error {
for _, s := range selectors {
if len(s.MatchArgs) > 0 ||
Expand All @@ -159,6 +229,7 @@ func isValidUprobeSelectors(selectors []v1alpha1.KProbeSelector) error {
type addUprobeIn struct {
sensorPath string
policyName string
useMulti bool
}

func createGenericUprobeSensor(
Expand All @@ -176,6 +247,7 @@ func createGenericUprobeSensor(
in := addUprobeIn{
sensorPath: name,
policyName: policyName,
useMulti: bpf.HasUprobeMulti(),
}

for _, spec := range uprobes {
Expand All @@ -185,7 +257,12 @@ func createGenericUprobeSensor(
}
}

progs, maps, err = createSingleUprobeSensor(sensorPath, ids)
if in.useMulti {
progs, maps, err = createMultiUprobeSensor(sensorPath, ids)
} else {
progs, maps, err = createSingleUprobeSensor(ids)
}

if err != nil {
return nil, err
}
Expand Down Expand Up @@ -224,7 +301,12 @@ func addUprobe(spec *v1alpha1.UProbeSpec, policyName string, ids []idtable.Entry
uprobeTable.AddEntry(uprobeEntry)
id := uprobeEntry.tableId

uprobeEntry.pinPathPrefix = sensors.PathJoin(in.sensorPath, fmt.Sprintf("%d", id.ID))
if in.useMulti {
uprobeEntry.pinPathPrefix = multiUprobePinPath(in.sensorPath)
} else {
uprobeEntry.pinPathPrefix = sensors.PathJoin(in.sensorPath, fmt.Sprintf("gup-%d", id.ID))
}

config.FuncId = uint32(id.ID)

if selectors.HasEarlyBinaryFilter(spec.Selectors) {
Expand All @@ -235,7 +317,40 @@ func addUprobe(spec *v1alpha1.UProbeSpec, policyName string, ids []idtable.Entry
return ids, nil
}

func createSingleUprobeSensor(sensorPath string, ids []idtable.EntryID) ([]*program.Program, []*program.Map, error) {
func multiUprobePinPath(sensorPath string) string {
return sensors.PathJoin(sensorPath, "multi_kprobe")
}

func createMultiUprobeSensor(sensorPath string, multiIDs []idtable.EntryID) ([]*program.Program, []*program.Map, error) {
var progs []*program.Program
var maps []*program.Map

loadProgName := "bpf_multi_uprobe_v61.o"

pinPath := multiUprobePinPath(sensorPath)

load := program.Builder(
path.Join(option.Config.HubbleLib, loadProgName),
fmt.Sprintf("%d functions", len(multiIDs)),
"uprobe.multi/generic_uprobe",
pinPath,
"generic_uprobe").
SetLoaderData(multiIDs)

progs = append(progs, load)

configMap := program.MapBuilderPin("config_map", sensors.PathJoin(pinPath, "config_map"), load)
tailCalls := program.MapBuilderPin("uprobe_calls", sensors.PathJoin(pinPath, "up_calls"), load)
filterMap := program.MapBuilderPin("filter_map", sensors.PathJoin(pinPath, "filter_map"), load)

maps = append(maps, configMap, tailCalls, filterMap)

filterMap.SetMaxEntries(len(multiIDs))
configMap.SetMaxEntries(len(multiIDs))
return progs, maps, nil
}

func createSingleUprobeSensor(ids []idtable.EntryID) ([]*program.Program, []*program.Map, error) {
var progs []*program.Program
var maps []*program.Map

Expand All @@ -244,13 +359,13 @@ func createSingleUprobeSensor(sensorPath string, ids []idtable.EntryID) ([]*prog
if err != nil {
return nil, nil, err
}
progs, maps = createUprobeSensorFromEntry(uprobeEntry, sensorPath, progs, maps)
progs, maps = createUprobeSensorFromEntry(uprobeEntry, progs, maps)
}

return progs, maps, nil
}

func createUprobeSensorFromEntry(uprobeEntry *genericUprobe, sensorPath string,
func createUprobeSensorFromEntry(uprobeEntry *genericUprobe,
progs []*program.Program, maps []*program.Map) ([]*program.Program, []*program.Map) {

loadProgName := "bpf_generic_uprobe.o"
Expand Down

0 comments on commit 2dac95e

Please sign in to comment.