From fc0e4490dd39a9301a3f1ae328267365573a3250 Mon Sep 17 00:00:00 2001 From: Alban Crequy Date: Wed, 10 May 2017 18:36:33 +0200 Subject: [PATCH] vendoring: update gobpf and tcptracer-bpf --- vendor/github.com/iovisor/gobpf/elf/elf.go | 38 +++++++++++++++---- .../iovisor/gobpf/elf/elf_unsupported.go | 11 +++--- vendor/github.com/iovisor/gobpf/elf/perf.go | 35 +++++++++-------- vendor/github.com/iovisor/gobpf/elf/table.go | 25 ++++++++++++ .../tcptracer-bpf/pkg/tracer/tracer.go | 28 +++++++++----- .../pkg/tracer/tracer_unsupported.go | 2 +- .../weaveworks/tcptracer-bpf/tests/tracer.go | 7 +++- vendor/manifest | 4 +- 8 files changed, 108 insertions(+), 42 deletions(-) diff --git a/vendor/github.com/iovisor/gobpf/elf/elf.go b/vendor/github.com/iovisor/gobpf/elf/elf.go index 4047136ca..753bdd187 100644 --- a/vendor/github.com/iovisor/gobpf/elf/elf.go +++ b/vendor/github.com/iovisor/gobpf/elf/elf.go @@ -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 { diff --git a/vendor/github.com/iovisor/gobpf/elf/elf_unsupported.go b/vendor/github.com/iovisor/gobpf/elf/elf_unsupported.go index 4c408e3fb..a459d1ce6 100644 --- a/vendor/github.com/iovisor/gobpf/elf/elf_unsupported.go +++ b/vendor/github.com/iovisor/gobpf/elf/elf_unsupported.go @@ -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 } diff --git a/vendor/github.com/iovisor/gobpf/elf/perf.go b/vendor/github.com/iovisor/gobpf/elf/perf.go index 2a9d467bb..a81d8ed2f 100644 --- a/vendor/github.com/iovisor/gobpf/elf/perf.go +++ b/vendor/github.com/iovisor/gobpf/elf/perf.go @@ -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 diff --git a/vendor/github.com/iovisor/gobpf/elf/table.go b/vendor/github.com/iovisor/gobpf/elf/table.go index e4a2e5ee1..b4c43c367 100644 --- a/vendor/github.com/iovisor/gobpf/elf/table.go +++ b/vendor/github.com/iovisor/gobpf/elf/table.go @@ -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 +} diff --git a/vendor/github.com/weaveworks/tcptracer-bpf/pkg/tracer/tracer.go b/vendor/github.com/weaveworks/tcptracer-bpf/pkg/tracer/tracer.go index 3e16f643a..b84ae0d1e 100644 --- a/vendor/github.com/weaveworks/tcptracer-bpf/pkg/tracer/tracer.go +++ b/vendor/github.com/weaveworks/tcptracer-bpf/pkg/tracer/tracer.go @@ -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) } diff --git a/vendor/github.com/weaveworks/tcptracer-bpf/pkg/tracer/tracer_unsupported.go b/vendor/github.com/weaveworks/tcptracer-bpf/pkg/tracer/tracer_unsupported.go index 9e94594b1..848dc2a22 100644 --- a/vendor/github.com/weaveworks/tcptracer-bpf/pkg/tracer/tracer_unsupported.go +++ b/vendor/github.com/weaveworks/tcptracer-bpf/pkg/tracer/tracer_unsupported.go @@ -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") } diff --git a/vendor/github.com/weaveworks/tcptracer-bpf/tests/tracer.go b/vendor/github.com/weaveworks/tcptracer-bpf/tests/tracer.go index fbe0eee88..ba491e999 100644 --- a/vendor/github.com/weaveworks/tcptracer-bpf/tests/tracer.go +++ b/vendor/github.com/weaveworks/tcptracer-bpf/tests/tracer.go @@ -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) diff --git a/vendor/manifest b/vendor/manifest index b939fd027..9c21dabe7 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -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 },