-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Let consumer application read packets(plain and tls) perf buffers dir…
…ectly (#121)
- Loading branch information
Showing
12 changed files
with
484 additions
and
99 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,8 @@ package bpf | |
|
||
import ( | ||
"fmt" | ||
"path/filepath" | ||
"strings" | ||
|
||
"bytes" | ||
"os" | ||
|
@@ -11,11 +13,18 @@ import ( | |
"github.com/cilium/ebpf/asm" | ||
"github.com/cilium/ebpf/features" | ||
"github.com/go-errors/errors" | ||
"github.com/kubeshark/tracer/misc" | ||
"github.com/kubeshark/tracer/pkg/utils" | ||
"github.com/moby/moby/pkg/parsers/kernel" | ||
"github.com/rs/zerolog/log" | ||
) | ||
|
||
const ( | ||
PinPath = "/sys/fs/bpf/kubeshark" | ||
PinNamePlainPackets = "packets_plain" | ||
PinNameTLSPackets = "packets_tls" | ||
) | ||
|
||
// TODO: cilium/ebpf does not support .kconfig Therefore; for now, we build object files per kernel version. | ||
|
||
//go:generate go run github.com/cilium/ebpf/cmd/[email protected] -target $BPF_TARGET -cflags $BPF_CFLAGS -type tls_chunk -type goid_offsets Tracer ../../bpf/tracer.c | ||
|
@@ -27,7 +36,7 @@ type BpfObjectsImpl struct { | |
specs *ebpf.CollectionSpec | ||
} | ||
|
||
func (objs *BpfObjectsImpl) loadBpfObjects(bpfConstants map[string]uint64, reader *bytes.Reader) error { | ||
func (objs *BpfObjectsImpl) loadBpfObjects(bpfConstants map[string]uint64, mapReplacements map[string]*ebpf.Map, reader *bytes.Reader) error { | ||
var err error | ||
|
||
objs.specs, err = ebpf.LoadCollectionSpecFromReader(reader) | ||
|
@@ -44,7 +53,10 @@ func (objs *BpfObjectsImpl) loadBpfObjects(bpfConstants map[string]uint64, reade | |
return err | ||
} | ||
|
||
err = objs.specs.LoadAndAssign(objs.bpfObjs, nil) | ||
opts := ebpf.CollectionOptions{ | ||
MapReplacements: mapReplacements, | ||
} | ||
err = objs.specs.LoadAndAssign(objs.bpfObjs, &opts) | ||
if err != nil { | ||
var ve *ebpf.VerifierError | ||
if errors.As(err, &ve) { | ||
|
@@ -59,8 +71,7 @@ func (objs *BpfObjectsImpl) loadBpfObjects(bpfConstants map[string]uint64, reade | |
} | ||
|
||
type BpfObjects struct { | ||
BpfObjs TracerObjects | ||
IsCgroupV2 bool | ||
BpfObjs TracerObjects | ||
} | ||
|
||
func programHelperExists(pt ebpf.ProgramType, helper asm.BuiltinFunc) uint64 { | ||
|
@@ -82,15 +93,41 @@ func NewBpfObjects(disableEbpfCapture bool) (*BpfObjects, error) { | |
} | ||
|
||
cgroupV1 := uint64(1) | ||
objs.IsCgroupV2, err = utils.IsCgroupV2() | ||
isCgroupV2, err := utils.IsCgroupV2() | ||
if err != nil { | ||
log.Error().Err(err).Msg("read cgroups information failed:") | ||
} | ||
if objs.IsCgroupV2 { | ||
if isCgroupV2 { | ||
cgroupV1 = 0 | ||
} | ||
|
||
log.Info().Msg(fmt.Sprintf("Detected Linux kernel version: %s cgroups version2: %v", kernelVersion, objs.IsCgroupV2)) | ||
mapReplacements := make(map[string]*ebpf.Map) | ||
plainPath := filepath.Join(PinPath, PinNamePlainPackets) | ||
tlsPath := filepath.Join(PinPath, PinNameTLSPackets) | ||
|
||
if !kernel.CheckKernelVersion(5, 4, 0) { | ||
disableEbpfCapture = true | ||
} | ||
|
||
markDisabledEBPF := func() error { | ||
pathNoEbpf := filepath.Join(misc.GetDataDir(), "noebpf") | ||
file, err := os.Create(pathNoEbpf) | ||
if err != nil { | ||
return err | ||
} | ||
file.Close() | ||
return nil | ||
} | ||
|
||
ebpfBackendStatus := "enabled" | ||
if disableEbpfCapture { | ||
ebpfBackendStatus = "disabled" | ||
if err = markDisabledEBPF(); err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
log.Info().Msg(fmt.Sprintf("Detected Linux kernel version: %s cgroups version2: %v, eBPF backend %v", kernelVersion, isCgroupV2, ebpfBackendStatus)) | ||
kernelVersionInt := uint64(1_000_000)*uint64(kernelVersion.Kernel) + uint64(1_000)*uint64(kernelVersion.Major) + uint64(kernelVersion.Minor) | ||
|
||
// TODO: cilium/ebpf does not support .kconfig Therefore; for now, we load object files according to kernel version. | ||
|
@@ -127,16 +164,70 @@ func NewBpfObjects(disableEbpfCapture bool) (*BpfObjects, error) { | |
"DISABLE_EBPF_CAPTURE": disableCapture, | ||
} | ||
|
||
err = objects.loadBpfObjects(bpfConsts, bytes.NewReader(_TracerBytes)) | ||
pktsBuffer, err := ebpf.LoadPinnedMap(plainPath, nil) | ||
if err == nil { | ||
objs.BpfObjs = *objects.bpfObjs.(*TracerObjects) | ||
mapReplacements["pkts_buffer"] = pktsBuffer | ||
log.Info().Str("path", tlsPath).Msg("loaded plain packets buffer") | ||
} else if !errors.Is(err, os.ErrNotExist) { | ||
log.Error().Msg(fmt.Sprintf("load plain packets map failed: %v", err)) | ||
} | ||
|
||
if err != nil { | ||
chunksBuffer, err := ebpf.LoadPinnedMap(tlsPath, nil) | ||
if err == nil { | ||
mapReplacements["chunks_buffer"] = chunksBuffer | ||
log.Info().Str("path", tlsPath).Msg("loaded tls packets buffer") | ||
} else if !errors.Is(err, os.ErrNotExist) { | ||
log.Error().Msg(fmt.Sprintf("load tls packets map failed: %v", err)) | ||
} | ||
|
||
err = objects.loadBpfObjects(bpfConsts, mapReplacements, bytes.NewReader(_TracerBytes)) | ||
if err == nil { | ||
objs.BpfObjs = *objects.bpfObjs.(*TracerObjects) | ||
} else if err != nil { | ||
log.Error().Msg(fmt.Sprintf("load bpf objects failed: %v", err)) | ||
return nil, err | ||
} | ||
} | ||
|
||
// Pin packet perf maps: | ||
|
||
defer func() { | ||
if os.IsPermission(err) || strings.Contains(fmt.Sprintf("%v", err), "permission") { | ||
log.Warn().Msg(fmt.Sprintf("There are no enough permissions to activate eBPF. Error: %v", err)) | ||
if err = markDisabledEBPF(); err != nil { | ||
log.Error().Err(err).Msg("disable ebpf failed") | ||
} else { | ||
err = nil | ||
} | ||
} | ||
}() | ||
|
||
if err = os.MkdirAll(PinPath, 0700); err != nil { | ||
log.Error().Msg(fmt.Sprintf("mkdir pin path failed: %v", err)) | ||
return nil, err | ||
} | ||
|
||
pinMap := func(mapName, path string, mapObj *ebpf.Map) error { | ||
if _, ok := mapReplacements[mapName]; !ok { | ||
if err = mapObj.Pin(path); err != nil { | ||
log.Error().Err(err).Str("path", path).Msg("pin perf buffer failed") | ||
return err | ||
} else { | ||
log.Info().Str("path", path).Msg("pinned perf buffer") | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
if !disableEbpfCapture { | ||
if err = pinMap("pkts_buffer", plainPath, objs.BpfObjs.PktsBuffer); err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
if err = pinMap("chunks_buffer", tlsPath, objs.BpfObjs.ChunksBuffer); err != nil { | ||
return nil, err | ||
} | ||
|
||
return &objs, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.