github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/pkg/ebpf/ebpf_linux.go (about) 1 // +build !rhel6 2 3 package ebpf 4 5 import ( 6 "bytes" 7 "encoding/binary" 8 "os" 9 "path/filepath" 10 "strconv" 11 "strings" 12 "unsafe" 13 14 bpflib "github.com/iovisor/gobpf/elf" 15 "github.com/iovisor/gobpf/pkg/bpffs" 16 provider "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/aclprovider" 17 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/connection" 18 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/ebpf/bpfbuild" 19 "go.uber.org/zap" 20 ) 21 22 type ebpfModule struct { 23 m *bpflib.Module 24 sessionMap *bpflib.Map 25 bpfPath string 26 } 27 28 type flow struct { 29 srcIP uint32 30 dstIP uint32 31 srcPort uint16 32 dstPort uint16 33 } 34 35 const bpfPath = "/sys/fs/bpf/" 36 const bpfPrefix = "app-ack" 37 38 func removeOldBPFFiles() { 39 40 removeFiles := func(path string, info os.FileInfo, err error) error { 41 if strings.Contains(path, bpfPrefix) { 42 if err := os.Remove(path); err != nil { 43 zap.L().Debug("Failed to remove file", zap.String("path", path), zap.Error(err)) 44 } 45 } 46 return nil 47 } 48 49 filepath.Walk(bpfPath, removeFiles) // nolint 50 } 51 52 // IsEBPFSupported is called once by the master enforcer to test if 53 // the system supports eBPF. 54 func IsEBPFSupported() bool { 55 56 if err := bpffs.Mount(); err != nil { 57 zap.L().Info("bpf mount failed", zap.Error(err)) 58 return false 59 } 60 61 var bpf BPFModule 62 63 if bpf = LoadBPF(); bpf == nil { 64 return false 65 } 66 67 if err := provider.TestIptablesPinned(bpf.GetBPFPath()); err != nil { 68 zap.L().Info("Kernel doesn't support iptables pinned path", zap.Error(err)) 69 return false 70 } 71 72 removeOldBPFFiles() 73 return true 74 } 75 76 // LoadBPF loads the bpf object in the memory and also pins the bpf to the file system. 77 func LoadBPF() BPFModule { 78 bpf := &ebpfModule{} 79 80 bpf.bpfPath = bpfPath + bpfPrefix + strconv.Itoa(os.Getpid()) 81 if err := os.Remove(bpf.bpfPath); err != nil { 82 if !os.IsNotExist(err) { 83 zap.L().Debug("Failed to remove bpf file", zap.Error(err)) 84 } 85 } 86 87 buf, err := bpfbuild.Asset("socket-filter-bpf.o") 88 if err != nil { 89 zap.L().Info("Failed to locate asset socket-filter-bpf", zap.Error(err)) 90 return nil 91 } 92 93 reader := bytes.NewReader(buf) 94 m := bpflib.NewModuleFromReader(reader) 95 96 if err := m.Load(nil); err != nil { 97 zap.L().Info("Failed to load BPF in kernel", zap.Error(err)) 98 return nil 99 } 100 101 sfAppAck := m.SocketFilter("socket/app_ack") 102 if sfAppAck == nil { 103 zap.L().Info("Failed to load socket filter app_ack") 104 return nil 105 } 106 107 if err := bpflib.PinObject(sfAppAck.Fd(), bpf.bpfPath); err != nil { 108 zap.L().Info("Failed to pin bpf to file system", zap.Error(err)) 109 return nil 110 } 111 112 sessionMap := m.Map("sessions") 113 if sessionMap == nil { 114 zap.L().Info("Failed to load sessions map") 115 return nil 116 } 117 118 bpf.m = m 119 bpf.sessionMap = sessionMap 120 121 return bpf 122 } 123 124 func (ebpf *ebpfModule) CreateFlow(tcpTuple *connection.TCPTuple) { 125 var key flow 126 var val uint8 127 128 key.srcIP = binary.BigEndian.Uint32(tcpTuple.SourceAddress) 129 key.dstIP = binary.BigEndian.Uint32(tcpTuple.DestinationAddress) 130 key.srcPort = tcpTuple.SourcePort 131 key.dstPort = tcpTuple.DestinationPort 132 133 val = 1 134 135 err := ebpf.m.UpdateElement(ebpf.sessionMap, unsafe.Pointer(&key), unsafe.Pointer(&val), 0) 136 if err != nil { 137 zap.L().Debug("Update bpf map failed", 138 zap.String("packet", tcpTuple.String()), 139 zap.Error(err)) 140 } 141 } 142 143 func (ebpf *ebpfModule) RemoveFlow(tcpTuple *connection.TCPTuple) { 144 var key flow 145 146 key.srcIP = binary.BigEndian.Uint32(tcpTuple.SourceAddress) 147 key.dstIP = binary.BigEndian.Uint32(tcpTuple.DestinationAddress) 148 key.srcPort = tcpTuple.SourcePort 149 key.dstPort = tcpTuple.DestinationPort 150 151 err := ebpf.m.DeleteElement(ebpf.sessionMap, unsafe.Pointer(&key)) 152 if err != nil { 153 zap.L().Debug("Delete bpf map failed", 154 zap.String("packet", tcpTuple.String()), 155 zap.Error(err)) 156 } 157 } 158 159 func (ebpf *ebpfModule) GetBPFPath() string { 160 return ebpf.bpfPath 161 } 162 163 func (ebpf *ebpfModule) Cleanup() { 164 if err := os.Remove(ebpf.bpfPath); err != nil { 165 zap.L().Error("Failed to remove bpf file during cleanup", zap.Error(err)) 166 } 167 }