-
Notifications
You must be signed in to change notification settings - Fork 51
/
ebpf_linux.go
167 lines (133 loc) · 3.86 KB
/
ebpf_linux.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// +build !rhel6
package ebpf
import (
"bytes"
"encoding/binary"
"os"
"path/filepath"
"strconv"
"strings"
"unsafe"
bpflib "github.com/iovisor/gobpf/elf"
"github.com/iovisor/gobpf/pkg/bpffs"
provider "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/aclprovider"
"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/connection"
"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/ebpf/bpfbuild"
"go.uber.org/zap"
)
type ebpfModule struct {
m *bpflib.Module
sessionMap *bpflib.Map
bpfPath string
}
type flow struct {
srcIP uint32
dstIP uint32
srcPort uint16
dstPort uint16
}
const bpfPath = "/sys/fs/bpf/"
const bpfPrefix = "app-ack"
func removeOldBPFFiles() {
removeFiles := func(path string, info os.FileInfo, err error) error {
if strings.Contains(path, bpfPrefix) {
if err := os.Remove(path); err != nil {
zap.L().Debug("Failed to remove file", zap.String("path", path), zap.Error(err))
}
}
return nil
}
filepath.Walk(bpfPath, removeFiles) // nolint
}
// IsEBPFSupported is called once by the master enforcer to test if
// the system supports eBPF.
func IsEBPFSupported() bool {
if err := bpffs.Mount(); err != nil {
zap.L().Info("bpf mount failed", zap.Error(err))
return false
}
var bpf BPFModule
if bpf = LoadBPF(); bpf == nil {
return false
}
if err := provider.TestIptablesPinned(bpf.GetBPFPath()); err != nil {
zap.L().Info("Kernel doesn't support iptables pinned path", zap.Error(err))
return false
}
removeOldBPFFiles()
return true
}
// LoadBPF loads the bpf object in the memory and also pins the bpf to the file system.
func LoadBPF() BPFModule {
bpf := &ebpfModule{}
bpf.bpfPath = bpfPath + bpfPrefix + strconv.Itoa(os.Getpid())
if err := os.Remove(bpf.bpfPath); err != nil {
if !os.IsNotExist(err) {
zap.L().Debug("Failed to remove bpf file", zap.Error(err))
}
}
buf, err := bpfbuild.Asset("socket-filter-bpf.o")
if err != nil {
zap.L().Info("Failed to locate asset socket-filter-bpf", zap.Error(err))
return nil
}
reader := bytes.NewReader(buf)
m := bpflib.NewModuleFromReader(reader)
if err := m.Load(nil); err != nil {
zap.L().Info("Failed to load BPF in kernel", zap.Error(err))
return nil
}
sfAppAck := m.SocketFilter("socket/app_ack")
if sfAppAck == nil {
zap.L().Info("Failed to load socket filter app_ack")
return nil
}
if err := bpflib.PinObject(sfAppAck.Fd(), bpf.bpfPath); err != nil {
zap.L().Info("Failed to pin bpf to file system", zap.Error(err))
return nil
}
sessionMap := m.Map("sessions")
if sessionMap == nil {
zap.L().Info("Failed to load sessions map")
return nil
}
bpf.m = m
bpf.sessionMap = sessionMap
return bpf
}
func (ebpf *ebpfModule) CreateFlow(tcpTuple *connection.TCPTuple) {
var key flow
var val uint8
key.srcIP = binary.BigEndian.Uint32(tcpTuple.SourceAddress)
key.dstIP = binary.BigEndian.Uint32(tcpTuple.DestinationAddress)
key.srcPort = tcpTuple.SourcePort
key.dstPort = tcpTuple.DestinationPort
val = 1
err := ebpf.m.UpdateElement(ebpf.sessionMap, unsafe.Pointer(&key), unsafe.Pointer(&val), 0)
if err != nil {
zap.L().Debug("Update bpf map failed",
zap.String("packet", tcpTuple.String()),
zap.Error(err))
}
}
func (ebpf *ebpfModule) RemoveFlow(tcpTuple *connection.TCPTuple) {
var key flow
key.srcIP = binary.BigEndian.Uint32(tcpTuple.SourceAddress)
key.dstIP = binary.BigEndian.Uint32(tcpTuple.DestinationAddress)
key.srcPort = tcpTuple.SourcePort
key.dstPort = tcpTuple.DestinationPort
err := ebpf.m.DeleteElement(ebpf.sessionMap, unsafe.Pointer(&key))
if err != nil {
zap.L().Debug("Delete bpf map failed",
zap.String("packet", tcpTuple.String()),
zap.Error(err))
}
}
func (ebpf *ebpfModule) GetBPFPath() string {
return ebpf.bpfPath
}
func (ebpf *ebpfModule) Cleanup() {
if err := os.Remove(ebpf.bpfPath); err != nil {
zap.L().Error("Failed to remove bpf file during cleanup", zap.Error(err))
}
}