vendoring: update gobpf and tcptracer-bpf

This commit is contained in:
Alban Crequy
2017-05-10 18:36:33 +02:00
parent 860dfb7b7a
commit fc0e4490dd
8 changed files with 108 additions and 42 deletions

View File

@@ -348,7 +348,14 @@ func (b *Module) relocate(data []byte, rdata []byte) error {
}
}
func (b *Module) Load() error {
type SectionParams struct {
PerfRingBufferPageCount int
SkipPerfMapInitialization bool
}
// Load loads the BPF programs and BPF maps in the module. Each ELF section
// can optionally have parameters that changes how it is configured.
func (b *Module) Load(parameters map[string]SectionParams) error {
if b.fileName != "" {
fileReader, err := os.Open(b.fileName)
if err != nil {
@@ -541,10 +548,10 @@ func (b *Module) Load() error {
}
}
return b.initializePerfMaps()
return b.initializePerfMaps(parameters)
}
func (b *Module) initializePerfMaps() error {
func (b *Module) initializePerfMaps(parameters map[string]SectionParams) error {
for name, m := range b.maps {
var cpu C.int = 0
@@ -552,6 +559,22 @@ func (b *Module) initializePerfMaps() error {
continue
}
pageSize := os.Getpagesize()
b.maps[name].pageCount = 8 // reasonable default
sectionName := "maps/" + name
if params, ok := parameters[sectionName]; ok {
if params.SkipPerfMapInitialization {
continue
}
if params.PerfRingBufferPageCount > 0 {
if params.PerfRingBufferPageCount <= 0 || (params.PerfRingBufferPageCount&(params.PerfRingBufferPageCount-1)) != 0 {
return fmt.Errorf("number of pages (%d) must be stricly positive and a power of 2", params.PerfRingBufferPageCount)
}
b.maps[name].pageCount = params.PerfRingBufferPageCount
}
}
for {
pmuFD, err := C.perf_event_open_map(-1 /* pid */, cpu /* cpu */, -1 /* group_fd */, C.PERF_FLAG_FD_CLOEXEC)
if pmuFD < 0 {
@@ -562,9 +585,7 @@ func (b *Module) initializePerfMaps() error {
}
// mmap
pageSize := os.Getpagesize()
pageCount := 8
mmapSize := pageSize * (pageCount + 1)
mmapSize := pageSize * (b.maps[name].pageCount + 1)
base, err := syscall.Mmap(int(pmuFD), 0, mmapSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
if err != nil {
@@ -602,8 +623,9 @@ type Map struct {
m *C.bpf_map
// only for perf maps
pmuFDs []C.int
headers []*C.struct_perf_event_mmap_page
pmuFDs []C.int
headers []*C.struct_perf_event_mmap_page
pageCount int
}
func (b *Module) IterMaps() <-chan *Map {

View File

@@ -6,12 +6,13 @@ import (
"fmt"
)
func (b *Module) Load() error {
return fmt.Errorf("not supported")
}
// not supported; dummy struct
type BPFKProbePerf struct{}
type SectionParams struct{}
func (b *Module) Load(parameters map[string]SectionParams) error {
return fmt.Errorf("not supported")
}
func NewBpfPerfEvent(fileName string) *BPFKProbePerf {
// not supported
@@ -22,7 +23,7 @@ func (b *BPFKProbePerf) Load() error {
return fmt.Errorf("not supported")
}
func (b *BPFKProbePerf) PollStart(mapName string, receiverChan chan []byte) {
func (b *BPFKProbePerf) PollStart(mapName string, receiverChan chan []byte, lostChan chan uint64) {
// not supported
return
}

View File

@@ -106,7 +106,9 @@ import "C"
type PerfMap struct {
name string
program *Module
pageCount int
receiverChan chan []byte
lostChan chan uint64
pollStop chan bool
timestamp func(*[]byte) uint64
}
@@ -118,8 +120,8 @@ type PerfEventSample struct {
data byte // Size bytes of data
}
func InitPerfMap(b *Module, mapName string, receiverChan chan []byte) (*PerfMap, error) {
_, ok := b.maps[mapName]
func InitPerfMap(b *Module, mapName string, receiverChan chan []byte, lostChan chan uint64) (*PerfMap, error) {
m, ok := b.maps[mapName]
if !ok {
return nil, fmt.Errorf("no map with name %s", mapName)
}
@@ -127,7 +129,9 @@ func InitPerfMap(b *Module, mapName string, receiverChan chan []byte) (*PerfMap,
return &PerfMap{
name: mapName,
program: b,
pageCount: m.pageCount,
receiverChan: receiverChan,
lostChan: lostChan,
pollStop: make(chan bool),
}, nil
}
@@ -157,7 +161,6 @@ func (pm *PerfMap) PollStart() {
go func() {
cpuCount := len(m.pmuFDs)
pageSize := os.Getpagesize()
pageCount := 8
state := C.struct_read_state{}
for {
@@ -168,59 +171,61 @@ func (pm *PerfMap) PollStart() {
perfEventPoll(m.pmuFDs)
}
harvestLoop:
for {
var harvestCount C.int
beforeHarvest := nowNanoseconds()
for cpu := 0; cpu < cpuCount; cpu++ {
ringBufferLoop:
for {
var sample *PerfEventSample
var lost *PerfEventLost
ok := C.perf_event_read(C.int(pageCount), C.int(pageSize),
ok := C.perf_event_read(C.int(pm.pageCount), C.int(pageSize),
unsafe.Pointer(&state), unsafe.Pointer(m.headers[cpu]),
unsafe.Pointer(&sample), unsafe.Pointer(&lost))
switch ok {
case 0:
break // nothing to read
break ringBufferLoop // nothing to read
case C.PERF_RECORD_SAMPLE:
size := sample.Size - 4
b := C.GoBytes(unsafe.Pointer(&sample.data), C.int(size))
incoming.bytesArray = append(incoming.bytesArray, b)
harvestCount++
if pm.timestamp == nil {
continue
continue ringBufferLoop
}
if incoming.timestamp(&b) > beforeHarvest {
// see comment below
break
} else {
continue
break ringBufferLoop
}
case C.PERF_RECORD_LOST:
if pm.lostChan != nil {
pm.lostChan <- lost.Lost
}
default:
// TODO: handle lost/unknown events?
// ignore unknown events
}
break
}
}
if incoming.timestamp != nil {
sort.Sort(incoming)
}
for i := 0; i < incoming.Len(); i++ {
for incoming.Len() > 0 {
if incoming.timestamp != nil && incoming.timestamp(&incoming.bytesArray[0]) > beforeHarvest {
// This record has been sent after the beginning of the harvest. Stop
// processing here to keep the order. "incoming" is sorted, so the next
// elements also must not be processed now.
break
break harvestLoop
}
pm.receiverChan <- incoming.bytesArray[0]
// remove first element
incoming.bytesArray = incoming.bytesArray[1:]
}
if harvestCount == 0 && len(incoming.bytesArray) == 0 {
break
break harvestLoop
}
}
}
@@ -265,7 +270,7 @@ func (a OrderedBytesArray) Swap(i, j int) {
}
func (a OrderedBytesArray) Less(i, j int) bool {
return *(*C.uint64_t)(unsafe.Pointer(&a.bytesArray[i][0])) < *(*C.uint64_t)(unsafe.Pointer(&a.bytesArray[j][0]))
return a.timestamp(&a.bytesArray[i]) < a.timestamp(&a.bytesArray[j])
}
// Matching 'struct perf_event_header in <linux/perf_event.h>

View File

@@ -106,3 +106,28 @@ func (b *Module) LookupElement(mp *Map, key, value unsafe.Pointer) error {
return nil
}
// DeleteElement deletes the given key in the the map stored in mp.
// The key is stored in the key unsafe.Pointer.
func (b *Module) DeleteElement(mp *Map, key unsafe.Pointer) error {
uba := C.union_bpf_attr{}
value := unsafe.Pointer(nil)
C.create_bpf_lookup_elem(
C.int(mp.m.fd),
key,
value,
unsafe.Pointer(&uba),
)
ret, _, err := syscall.Syscall(
C.__NR_bpf,
C.BPF_MAP_DELETE_ELEM,
uintptr(unsafe.Pointer(&uba)),
unsafe.Sizeof(uba),
)
if ret != 0 || err != 0 {
return fmt.Errorf("unable to delete element: %s", err)
}
return nil
}

View File

@@ -30,7 +30,7 @@ func TracerAsset() ([]byte, error) {
return buf, nil
}
func NewTracer(tcpEventCbV4 func(TcpV4), tcpEventCbV6 func(TcpV6)) (*Tracer, error) {
func NewTracer(tcpEventCbV4 func(TcpV4), tcpEventCbV6 func(TcpV6), lostCb func(lost uint64)) (*Tracer, error) {
buf, err := Asset("tcptracer-ebpf.o")
if err != nil {
return nil, fmt.Errorf("couldn't find asset: %s", err)
@@ -42,7 +42,9 @@ func NewTracer(tcpEventCbV4 func(TcpV4), tcpEventCbV6 func(TcpV6)) (*Tracer, err
return nil, fmt.Errorf("BPF not supported")
}
err = m.Load()
sectionParams := make(map[string]bpflib.SectionParams)
sectionParams["maps/tcp_event_ipv4"] = bpflib.SectionParams{PerfRingBufferPageCount: 256}
err = m.Load(sectionParams)
if err != nil {
return nil, err
}
@@ -54,13 +56,15 @@ func NewTracer(tcpEventCbV4 func(TcpV4), tcpEventCbV6 func(TcpV6)) (*Tracer, err
channelV4 := make(chan []byte)
channelV6 := make(chan []byte)
lostChanV4 := make(chan uint64)
lostChanV6 := make(chan uint64)
perfMapIPV4, err := initializeIPv4(m, channelV4)
perfMapIPV4, err := initializeIPv4(m, channelV4, lostChanV4)
if err != nil {
return nil, fmt.Errorf("failed to init perf map for IPv4 events: %s", err)
}
perfMapIPV6, err := initializeIPv6(m, channelV6)
perfMapIPV6, err := initializeIPv6(m, channelV6, lostChanV6)
if err != nil {
return nil, fmt.Errorf("failed to init perf map for IPv6 events: %s", err)
}
@@ -77,6 +81,8 @@ func NewTracer(tcpEventCbV4 func(TcpV4), tcpEventCbV6 func(TcpV6)) (*Tracer, err
return
case data := <-channelV4:
tcpEventCbV4(tcpV4ToGo(&data))
case lost := <-lostChanV4:
lostCb(lost)
}
}
}()
@@ -88,6 +94,8 @@ func NewTracer(tcpEventCbV4 func(TcpV4), tcpEventCbV6 func(TcpV6)) (*Tracer, err
return
case data := <-channelV6:
tcpEventCbV6(tcpV6ToGo(&data))
case lost := <-lostChanV6:
lostCb(lost)
}
}
}()
@@ -109,12 +117,12 @@ func (t *Tracer) Stop() {
t.perfMapIPV6.PollStop()
}
func initialize(module *bpflib.Module, eventMapName string, eventChan chan []byte) (*bpflib.PerfMap, error) {
func initialize(module *bpflib.Module, eventMapName string, eventChan chan []byte, lostChan chan uint64) (*bpflib.PerfMap, error) {
if err := guess(module); err != nil {
return nil, fmt.Errorf("error guessing offsets: %v", err)
}
pm, err := bpflib.InitPerfMap(module, eventMapName, eventChan)
pm, err := bpflib.InitPerfMap(module, eventMapName, eventChan, lostChan)
if err != nil {
return nil, fmt.Errorf("error initializing perf map for %q: %v", eventMapName, err)
}
@@ -123,10 +131,10 @@ func initialize(module *bpflib.Module, eventMapName string, eventChan chan []byt
}
func initializeIPv4(module *bpflib.Module, eventChan chan []byte) (*bpflib.PerfMap, error) {
return initialize(module, "tcp_event_ipv4", eventChan)
func initializeIPv4(module *bpflib.Module, eventChan chan []byte, lostChan chan uint64) (*bpflib.PerfMap, error) {
return initialize(module, "tcp_event_ipv4", eventChan, lostChan)
}
func initializeIPv6(module *bpflib.Module, eventChan chan []byte) (*bpflib.PerfMap, error) {
return initialize(module, "tcp_event_ipv6", eventChan)
func initializeIPv6(module *bpflib.Module, eventChan chan []byte, lostChan chan uint64) (*bpflib.PerfMap, error) {
return initialize(module, "tcp_event_ipv6", eventChan, lostChan)
}

View File

@@ -12,7 +12,7 @@ func TracerAsset() ([]byte, error) {
return nil, fmt.Errorf("not supported on non-Linux systems")
}
func NewTracer(tcpEventCbV4 func(TcpV4), tcpEventCbV6 func(TcpV6)) (*Tracer, error) {
func NewTracer(tcpEventCbV4 func(TcpV4), tcpEventCbV6 func(TcpV6), lostCb func(lost uint64)) (*Tracer, error) {
return nil, fmt.Errorf("not supported on non-Linux systems")
}

View File

@@ -35,13 +35,18 @@ func tcpEventCbV6(e tracer.TcpV6) {
lastTimestampV6 = e.Timestamp
}
func lostCb(count uint64) {
fmt.Printf("ERROR: lost %d events!\n", count)
os.Exit(1)
}
func main() {
if len(os.Args) != 1 {
fmt.Fprintf(os.Stderr, "Usage: %s\n", os.Args[0])
os.Exit(1)
}
t, err := tracer.NewTracer(tcpEventCbV4, tcpEventCbV6)
t, err := tracer.NewTracer(tcpEventCbV4, tcpEventCbV6, lostCb)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)

4
vendor/manifest vendored
View File

@@ -1020,7 +1020,7 @@
"importpath": "github.com/iovisor/gobpf/elf",
"repository": "https://github.com/iovisor/gobpf",
"vcs": "git",
"revision": "65e4048660d6c4339ebae113ac55b1af6f01305d",
"revision": "23f7ee81c1cc244d16ddc8110c2ec8b8a09d0448",
"branch": "master",
"path": "/elf",
"notests": true
@@ -1462,7 +1462,7 @@
"importpath": "github.com/weaveworks/tcptracer-bpf",
"repository": "https://github.com/weaveworks/tcptracer-bpf",
"vcs": "git",
"revision": "b715a3b635b8d9c4a096bbd6009826b57fe64c38",
"revision": "a82fffdbfee2ffe2c469279dbfeb3734cf7de1f2",
"branch": "master",
"notests": true
},