Skip to content

Commit b9eaba8

Browse files
rafaelroquettojdbaldry
andauthoredJan 16, 2025··
Add support for auto detecting TCX (#1533)
--------- Co-authored-by: Jack Baldry <jack.baldry@grafana.com>
1 parent 5a281d0 commit b9eaba8

File tree

7 files changed

+75
-10
lines changed

7 files changed

+75
-10
lines changed
 

‎.github/workflows/vale.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ jobs:
1212
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
1313
with:
1414
persist-credentials: false
15-
- uses: grafana/writers-toolkit/vale-action@4b1248585248751e3b12fd020cf7ac91540ca09c # vale-action/v1.0.0
15+
- uses: grafana/writers-toolkit/vale-action@13205961f20ad13843505a9b84fdf032f911a3f4 # vale-action/v1.1.0
1616
with:
1717
token: ${{ secrets.GITHUB_TOKEN }}

‎.vale.ini

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ MinAlertLevel = warning
22

33
[*]
44
BasedOnStyles = Grafana
5+
TokenIgnores = (<http[^\n]+>+?), \*\*[^\n]+\*\*

‎docs/sources/configure/options.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -500,17 +500,18 @@ generation of Beyla metrics.
500500

501501
| YAML | Environment variable | Type | Default |
502502
| ------------------------- | --------------------------------- | ------- | ------- |
503-
| `traffic_control_backend` | `BEYLA_BPF_TC_BACKEND` | string | `tc` |
503+
| `traffic_control_backend` | `BEYLA_BPF_TC_BACKEND` | string | `auto` |
504504

505505
Chooses which backend to use for the attachment of traffic control probes.
506506
Linux 6.6 has added support for a file-descriptor based traffic control
507507
attachment called TCX, providing a more robust way of attaching traffic
508508
control probes (it does not require explicit qdisc management, and provides a
509-
deterministic way to chain probes). We recommend the usage of the `tcx`
510-
backend for kernels >= 6.6 for this reason.
509+
deterministic way to chain probes).
510+
We recommend the usage of the `tcx` backend for kernels >= 6.6 for this reason.
511+
When set to `auto`, Beyla picks the most suitable backend based on the underlying kernel.
511512

512-
The accepted backends are `tc` and `tcx`. An empty or unset value defaults to
513-
`tc`.
513+
The accepted backends are `tc`, `tcx`, and `auto.
514+
An empty or unset value defaults to `auto`.
514515

515516
| YAML | Environment variable | Type | Default |
516517
| ----------------------- | ---------------------------------- | ------- | ------- |

‎pkg/beyla/config.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ var DefaultConfig = Config{
4949
BatchLength: 100,
5050
BatchTimeout: time.Second,
5151
HTTPRequestTimeout: 30 * time.Second,
52-
TCBackend: tcmanager.TCBackendTC,
52+
TCBackend: tcmanager.TCBackendAuto,
5353
},
5454
Grafana: otel.GrafanaConfig{
5555
OTLP: otel.GrafanaOTLP{

‎pkg/beyla/config_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ network:
125125
BatchLength: 100,
126126
BatchTimeout: time.Second,
127127
HTTPRequestTimeout: 30 * time.Second,
128-
TCBackend: tcmanager.TCBackendTC,
128+
TCBackend: tcmanager.TCBackendAuto,
129129
},
130130
Grafana: otel.GrafanaConfig{
131131
OTLP: otel.GrafanaOTLP{

‎pkg/internal/ebpf/tcmanager/ifacemanager.go

+4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ func NewInterfaceManager() *InterfaceManager {
4848
}
4949

5050
func (im *InterfaceManager) Start(ctx context.Context) {
51+
im.log.Debug("Starting InterfaceManager", "monitor_mode", im.monitorMode)
52+
5153
if im.registerer != nil {
5254
return
5355
}
@@ -62,6 +64,8 @@ func (im *InterfaceManager) Start(ctx context.Context) {
6264

6365
registerer := ifaces.NewRegisterer(informer, im.channelBufferLen)
6466

67+
im.log.Debug("Subscribing for events")
68+
6569
ifaceEvents, err := registerer.Subscribe(ctx)
6670

6771
if err != nil {

‎pkg/internal/ebpf/tcmanager/tcmanager.go

+61-2
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,22 @@ package tcmanager
44

55
import (
66
"fmt"
7+
"log/slog"
78
"strings"
9+
"sync"
810
"time"
911

1012
"github.com/cilium/ebpf"
13+
"github.com/cilium/ebpf/asm"
14+
"github.com/cilium/ebpf/link"
1115
)
1216

1317
type TCBackend uint8
1418

1519
const (
1620
TCBackendTC = TCBackend(iota + 1)
1721
TCBackendTCX
22+
TCBackendAuto
1823
)
1924

2025
type AttachmentType uint8
@@ -42,15 +47,32 @@ type TCManager interface {
4247
SetInterfaceManager(im *InterfaceManager)
4348
}
4449

50+
func newTCManagerAuto() TCManager {
51+
log := slog.With("component", "tc_manager")
52+
53+
log.Debug("Auto detecting TCX support")
54+
55+
if IsTCXSupported() {
56+
log.Debug("TCX support detected")
57+
return NewTCXManager()
58+
}
59+
60+
log.Debug("TCX not supported, using netlink")
61+
62+
return NewNetlinkManager()
63+
}
64+
4565
func NewTCManager(backend TCBackend) TCManager {
4666
switch backend {
4767
case TCBackendTC:
4868
return NewNetlinkManager()
4969
case TCBackendTCX:
5070
return NewTCXManager()
71+
case TCBackendAuto:
72+
return newTCManagerAuto()
5173
}
5274

53-
return NewNetlinkManager() // default
75+
return newTCManagerAuto() // default
5476
}
5577

5678
func (b *TCBackend) UnmarshalText(text []byte) error {
@@ -61,16 +83,53 @@ func (b *TCBackend) UnmarshalText(text []byte) error {
6183
case "tcx":
6284
*b = TCBackendTCX
6385
return nil
86+
case "auto":
87+
*b = TCBackendAuto
88+
return nil
6489
}
6590

6691
return fmt.Errorf("invalid TCBakend value: '%s'", text)
6792
}
6893

6994
func (b TCBackend) Valid() bool {
7095
switch b {
71-
case TCBackendTC, TCBackendTCX:
96+
case TCBackendTC, TCBackendTCX, TCBackendAuto:
7297
return true
7398
}
7499

75100
return false
76101
}
102+
103+
var IsTCXSupported = sync.OnceValue(func() bool {
104+
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
105+
Type: ebpf.SchedCLS,
106+
Instructions: asm.Instructions{
107+
asm.Mov.Imm(asm.R0, 0),
108+
asm.Return(),
109+
},
110+
License: "Apache-2.0",
111+
})
112+
113+
if err != nil {
114+
return false
115+
}
116+
117+
defer prog.Close()
118+
119+
l, err := link.AttachTCX(link.TCXOptions{
120+
Program: prog,
121+
Attach: ebpf.AttachTCXIngress,
122+
Interface: 1, // lo
123+
Anchor: link.Tail(),
124+
})
125+
126+
if err != nil {
127+
return false
128+
}
129+
130+
if err := l.Close(); err != nil {
131+
return false
132+
}
133+
134+
return true
135+
})

0 commit comments

Comments
 (0)
Please sign in to comment.