Skip to content

Commit 1b8236b

Browse files
hmahmoodbrycekahle
andauthored
[NPM-3378] Adding eBPF-less network tracer POC (#27100)
Co-authored-by: Bryce Kahle <bryce.kahle@datadoghq.com>
1 parent af65bcc commit 1b8236b

33 files changed

+1863
-898
lines changed

cmd/system-probe/config/adjust_npm.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const (
2525
)
2626

2727
func adjustNetwork(cfg config.Config) {
28+
ebpflessEnabled := cfg.GetBool(netNS("enable_ebpfless"))
29+
2830
limitMaxInt(cfg, spNS("max_conns_per_message"), maxConnsMessageBatchSize)
2931

3032
if cfg.GetBool(spNS("disable_tcp")) {
@@ -99,4 +101,24 @@ func adjustNetwork(cfg config.Config) {
99101
log.Warn("disabling NPM connection rollups since USM connection rollups are not enabled")
100102
cfg.Set(netNS("enable_connection_rollup"), false, model.SourceAgentRuntime)
101103
}
104+
105+
// disable features that are not supported on certain
106+
// configs/platforms
107+
var disableConfigs []struct {
108+
key, reason string
109+
}
110+
if ebpflessEnabled {
111+
const notSupportedEbpfless = "not supported when ebpf-less is enabled"
112+
disableConfigs = append(disableConfigs, []struct{ key, reason string }{
113+
{netNS("enable_protocol_classification"), notSupportedEbpfless},
114+
{evNS("network_process", "enabled"), notSupportedEbpfless}}...,
115+
)
116+
}
117+
118+
for _, c := range disableConfigs {
119+
if cfg.GetBool(c.key) {
120+
log.Warnf("disabling %s: %s", c.key, c.reason)
121+
cfg.Set(c.key, false, model.SourceAgentRuntime)
122+
}
123+
}
102124
}

cmd/system-probe/modules/network_tracer_linux.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,13 @@ package modules
1010
import (
1111
"github.com/DataDog/datadog-agent/cmd/system-probe/api/module"
1212
"github.com/DataDog/datadog-agent/cmd/system-probe/config"
13+
"github.com/DataDog/datadog-agent/pkg/network/tracer"
1314
)
1415

1516
// NetworkTracer is a factory for NPM's tracer
1617
var NetworkTracer = module.Factory{
1718
Name: config.NetworkTracerModule,
1819
ConfigNamespaces: networkTracerModuleConfigNamespaces,
1920
Fn: createNetworkTracerModule,
20-
NeedsEBPF: func() bool {
21-
return true
22-
},
21+
NeedsEBPF: tracer.NeedsEBPF,
2322
}

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,3 +1075,5 @@ replace (
10751075

10761076
// Prevent a false-positive detection by the Google and Ikarus security vendors on VirusTotal
10771077
exclude go.opentelemetry.io/proto/otlp v1.1.0
1078+
1079+
replace github.com/google/gopacket v1.1.19 => github.com/DataDog/gopacket v0.0.0-20240626205202-4ac4cee31f14

go.sum

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/config/setup/system_probe.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ func InitSystemProbeConfig(cfg pkgconfigmodel.Config) {
299299
// connection aggregation with port rollups
300300
cfg.BindEnvAndSetDefault(join(netNS, "enable_connection_rollup"), false)
301301

302+
cfg.BindEnvAndSetDefault(join(netNS, "enable_ebpfless"), false)
303+
302304
// windows config
303305
cfg.BindEnvAndSetDefault(join(spNS, "windows.enable_monotonic_count"), false)
304306

pkg/ebpf/ebpftest/buildmode.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ var (
1616
RuntimeCompiled BuildMode
1717
CORE BuildMode
1818
Fentry BuildMode
19+
Ebpfless BuildMode
1920
)
2021

2122
func init() {
2223
Prebuilt = prebuilt{}
2324
RuntimeCompiled = runtimeCompiled{}
2425
CORE = core{}
2526
Fentry = fentry{}
27+
Ebpfless = ebpfless{}
2628
}
2729

2830
// BuildMode is an eBPF build mode
@@ -95,6 +97,23 @@ func (f fentry) Env() map[string]string {
9597
}
9698
}
9799

100+
type ebpfless struct{}
101+
102+
func (e ebpfless) String() string {
103+
return "eBPFless"
104+
}
105+
106+
func (e ebpfless) Env() map[string]string {
107+
return map[string]string{
108+
"NETWORK_TRACER_FENTRY_TESTS": "false",
109+
"DD_ENABLE_RUNTIME_COMPILER": "false",
110+
"DD_ENABLE_CO_RE": "false",
111+
"DD_ALLOW_RUNTIME_COMPILED_FALLBACK": "false",
112+
"DD_ALLOW_PRECOMPILED_FALLBACK": "false",
113+
"DD_NETWORK_CONFIG_ENABLE_EBPFLESS": "true",
114+
}
115+
}
116+
98117
// GetBuildMode returns which build mode the current environment matches, if any
99118
func GetBuildMode() BuildMode {
100119
for _, mode := range []BuildMode{Prebuilt, RuntimeCompiled, CORE, Fentry} {

pkg/ebpf/ebpftest/buildmode_linux.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ func SupportedBuildModes() []BuildMode {
3030
(runtime.GOARCH == "amd64" && (hostPlatform == "amazon" || hostPlatform == "amzn") && kv.Major() == 5 && kv.Minor() == 10) {
3131
modes = append(modes, Fentry)
3232
}
33+
if os.Getenv("TEST_EBPFLESS_OVERRIDE") == "true" {
34+
modes = append(modes, Ebpfless)
35+
}
36+
3337
return modes
3438
}
3539

pkg/network/config/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ type Config struct {
302302
// buffers (>=5.8) will result in forcing the use of Perf Maps instead.
303303
EnableUSMRingBuffers bool
304304

305+
EnableEbpfless bool
306+
305307
// EnableUSMEventStream enables USM to use the event stream instead
306308
// of netlink for receiving process events.
307309
EnableUSMEventStream bool
@@ -406,6 +408,8 @@ func New() *Config {
406408

407409
EnableNPMConnectionRollup: cfg.GetBool(join(netNS, "enable_connection_rollup")),
408410

411+
EnableEbpfless: cfg.GetBool(join(netNS, "enable_ebpfless")),
412+
409413
// Service Monitoring
410414
EnableJavaTLSSupport: cfg.GetBool(join(smjtNS, "enabled")),
411415
JavaAgentDebug: cfg.GetBool(join(smjtNS, "debug")),

pkg/network/dns/driver_windows.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"github.com/DataDog/datadog-agent/comp/core/telemetry"
2525
"github.com/DataDog/datadog-agent/pkg/network/driver"
26+
"github.com/DataDog/datadog-agent/pkg/network/filter"
2627
)
2728

2829
const (
@@ -99,7 +100,7 @@ func (d *dnsDriver) SetDataFilters(filters []driver.FilterDefinition) error {
99100
}
100101

101102
// ReadDNSPacket visits a raw DNS packet if one is available.
102-
func (d *dnsDriver) ReadDNSPacket(visit func([]byte, time.Time) error) (didRead bool, err error) {
103+
func (d *dnsDriver) ReadDNSPacket(visit func(data []byte, info filter.PacketInfo, t time.Time) error) (didRead bool, err error) {
103104
var bytesRead uint32
104105
var key uintptr // returned by GetQueuedCompletionStatus, then ignored
105106
var ol *windows.Overlapped
@@ -125,7 +126,7 @@ func (d *dnsDriver) ReadDNSPacket(visit func([]byte, time.Time) error) (didRead
125126

126127
start := driver.FilterPacketHeaderSize
127128

128-
if err := visit(buf.data[start:], captureTime); err != nil {
129+
if err := visit(buf.data[start:], nil, captureTime); err != nil {
129130
return false, err
130131
}
131132

pkg/network/dns/monitor_linux.go

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,14 @@ import (
1111
"fmt"
1212
"math"
1313

14-
"golang.org/x/net/bpf"
15-
16-
"github.com/vishvananda/netns"
17-
1814
manager "github.com/DataDog/ebpf-manager"
15+
"github.com/vishvananda/netns"
1916

2017
"github.com/DataDog/datadog-agent/comp/core/telemetry"
2118
ddebpf "github.com/DataDog/datadog-agent/pkg/ebpf"
2219
"github.com/DataDog/datadog-agent/pkg/network/config"
2320
"github.com/DataDog/datadog-agent/pkg/network/ebpf/probes"
24-
filterpkg "github.com/DataDog/datadog-agent/pkg/network/filter"
21+
"github.com/DataDog/datadog-agent/pkg/network/filter"
2522
"github.com/DataDog/datadog-agent/pkg/util/kernel"
2623
"github.com/DataDog/datadog-agent/pkg/util/log"
2724
)
@@ -33,6 +30,26 @@ type dnsMonitor struct {
3330

3431
// NewReverseDNS starts snooping on DNS traffic to allow IP -> domain reverse resolution
3532
func NewReverseDNS(cfg *config.Config, _ telemetry.Component) (ReverseDNS, error) {
33+
// Create the RAW_SOCKET inside the root network namespace
34+
var (
35+
packetSrc *filter.AFPacketSource
36+
srcErr error
37+
ns netns.NsHandle
38+
)
39+
ns, err := cfg.GetRootNetNs()
40+
if err != nil {
41+
return nil, err
42+
}
43+
defer ns.Close()
44+
45+
err = kernel.WithNS(ns, func() error {
46+
packetSrc, srcErr = filter.NewAFPacketSource(4 << 20) // 4 MB total
47+
return srcErr
48+
})
49+
if err != nil {
50+
return nil, err
51+
}
52+
3653
currKernelVersion, err := kernel.HostVersion()
3754
if err != nil {
3855
// if the platform couldn't be determined, treat it as new kernel case
@@ -42,12 +59,11 @@ func NewReverseDNS(cfg *config.Config, _ telemetry.Component) (ReverseDNS, error
4259
pre410Kernel := currKernelVersion < kernel.VersionCode(4, 1, 0)
4360

4461
var p *ebpfProgram
45-
var filter *manager.Probe
46-
var bpfFilter []bpf.RawInstruction
47-
if pre410Kernel {
48-
bpfFilter, err = generateBPFFilter(cfg)
49-
if err != nil {
62+
if pre410Kernel || cfg.EnableEbpfless {
63+
if bpfFilter, err := generateBPFFilter(cfg); err != nil {
5064
return nil, fmt.Errorf("error creating bpf classic filter: %w", err)
65+
} else if err = packetSrc.SetBPF(bpfFilter); err != nil {
66+
return nil, fmt.Errorf("could not set BPF filter on packet source: %w", err)
5167
}
5268
} else {
5369
p, err = newEBPFProgram(cfg)
@@ -59,35 +75,21 @@ func NewReverseDNS(cfg *config.Config, _ telemetry.Component) (ReverseDNS, error
5975
return nil, fmt.Errorf("error initializing ebpf programs: %w", err)
6076
}
6177

62-
filter, _ = p.GetProbe(manager.ProbeIdentificationPair{EBPFFuncName: probes.SocketDNSFilter, UID: probeUID})
78+
filter, _ := p.GetProbe(manager.ProbeIdentificationPair{EBPFFuncName: probes.SocketDNSFilter, UID: probeUID})
6379
if filter == nil {
6480
return nil, fmt.Errorf("error retrieving socket filter")
6581
}
66-
}
6782

68-
// Create the RAW_SOCKET inside the root network namespace
69-
var (
70-
packetSrc *filterpkg.AFPacketSource
71-
srcErr error
72-
ns netns.NsHandle
73-
)
74-
if ns, err = cfg.GetRootNetNs(); err != nil {
75-
return nil, err
76-
}
77-
defer ns.Close()
78-
79-
err = kernel.WithNS(ns, func() error {
80-
packetSrc, srcErr = filterpkg.NewPacketSource(filter, bpfFilter)
81-
return srcErr
82-
})
83-
if err != nil {
84-
return nil, err
83+
if err = packetSrc.SetEbpf(filter); err != nil {
84+
return nil, fmt.Errorf("could not set file descriptor for eBPF program: %w", err)
85+
}
8586
}
8687

8788
snoop, err := newSocketFilterSnooper(cfg, packetSrc)
8889
if err != nil {
8990
return nil, err
9091
}
92+
9193
return &dnsMonitor{
9294
snoop,
9395
p,

0 commit comments

Comments
 (0)