-
Notifications
You must be signed in to change notification settings - Fork 115
/
Copy pathtcmanager.go
135 lines (107 loc) · 2.29 KB
/
tcmanager.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// line below avoids linter errors on Mac
// nolint:unused
package tcmanager
import (
"fmt"
"log/slog"
"strings"
"sync"
"time"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/asm"
"github.com/cilium/ebpf/link"
)
type TCBackend uint8
const (
TCBackendTC = TCBackend(iota + 1)
TCBackendTCX
TCBackendAuto
)
type AttachmentType uint8
const (
AttachmentEgress = AttachmentType(iota)
AttachmentIngress
)
type MonitorMode uint8
const (
MonitorPoll = MonitorMode(iota)
MonitorWatch
)
const DefaultMonitorMode = MonitorMode(MonitorWatch)
const DefaultChannelBufferLen = 10
const DefaultPollPeriod = 10 * time.Second
type TCManager interface {
Shutdown()
AddProgram(name string, prog *ebpf.Program, attachment AttachmentType)
RemoveProgram(name string)
SetInterfaceManager(im *InterfaceManager)
}
func newTCManagerAuto() TCManager {
log := slog.With("component", "tc_manager")
log.Debug("Auto detecting TCX support")
if IsTCXSupported() {
log.Debug("TCX support detected")
return NewTCXManager()
}
log.Debug("TCX not supported, using netlink")
return NewNetlinkManager()
}
func NewTCManager(backend TCBackend) TCManager {
switch backend {
case TCBackendTC:
return NewNetlinkManager()
case TCBackendTCX:
return NewTCXManager()
case TCBackendAuto:
return newTCManagerAuto()
}
return newTCManagerAuto() // default
}
func (b *TCBackend) UnmarshalText(text []byte) error {
switch strings.TrimSpace(string(text)) {
case "tc":
*b = TCBackendTC
return nil
case "tcx":
*b = TCBackendTCX
return nil
case "auto":
*b = TCBackendAuto
return nil
}
return fmt.Errorf("invalid TCBakend value: '%s'", text)
}
func (b TCBackend) Valid() bool {
switch b {
case TCBackendTC, TCBackendTCX, TCBackendAuto:
return true
}
return false
}
var IsTCXSupported = sync.OnceValue(func() bool {
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
Type: ebpf.SchedCLS,
Instructions: asm.Instructions{
asm.Mov.Imm(asm.R0, 0),
asm.Return(),
},
License: "Apache-2.0",
})
if err != nil {
return false
}
defer prog.Close()
l, err := link.AttachTCX(link.TCXOptions{
Program: prog,
Attach: ebpf.AttachTCXIngress,
Interface: 1, // lo
Anchor: link.Tail(),
})
if err != nil {
return false
}
if err := l.Close(); err != nil {
return false
}
return true
})