vendor: bump tcptracer-bpf

We found out we were losing kretprobes sometimes because maxactive was set too
low[1]. This problem was more apparent in our GCE test environment because
the kernel was configured with `CONFIG_PREEMPT` not set and we're running
single-core VMs (see https://github.com/weaveworks/tcptracer-bpf/issues/24 for
more details).

Unfortunately, we can't set the maxactive explicitly from userspace. Alban
submitted a kernel patch to allow this[2].

This bumps tcptracer-bpf to include a workaround[3] for this issue in the
guess-offsets phase.

[1]: https://github.com/weaveworks/tcptracer-bpf/issues/24
[2]: https://lkml.org/lkml/2017/3/28/629
[3]: https://github.com/weaveworks/tcptracer-bpf/pull/33
This commit is contained in:
Iago López Galeiras
2017-03-29 15:37:37 +02:00
parent 43720bd7c7
commit 7541ad9c9c
5 changed files with 37 additions and 8 deletions

View File

@@ -8,6 +8,7 @@ import (
"math/rand"
"net"
"os"
"runtime"
"strconv"
"strings"
"syscall"
@@ -227,7 +228,7 @@ func tryCurrentOffset(module *elf.Module, mp *elf.Map, status *tcpTracerStatus,
// checkAndUpdateCurrentOffset checks the value for the current offset stored
// in the eBPF map against the expected value, incrementing the offset if it
// doesn't match, or going to the next field to guess if it does
func checkAndUpdateCurrentOffset(module *elf.Module, mp *elf.Map, status *tcpTracerStatus, expected *fieldValues) error {
func checkAndUpdateCurrentOffset(module *elf.Module, mp *elf.Map, status *tcpTracerStatus, expected *fieldValues, maxRetries *int) error {
// get the updated map value so we can check if the current offset is
// the right one
if err := module.LookupElement(mp, unsafe.Pointer(&zero), unsafe.Pointer(status)); err != nil {
@@ -235,7 +236,14 @@ func checkAndUpdateCurrentOffset(module *elf.Module, mp *elf.Map, status *tcpTra
}
if status.state != stateChecked {
return fmt.Errorf("invalid guessing state while guessing %v, got %v expected %v", whatString[status.what], stateString[status.state], stateString[stateChecked])
if *maxRetries == 0 {
return fmt.Errorf("invalid guessing state while guessing %v, got %v expected %v",
whatString[status.what], stateString[status.state], stateString[stateChecked])
} else {
*maxRetries--
time.Sleep(10 * time.Millisecond)
return nil
}
}
switch status.what {
@@ -334,6 +342,11 @@ func guess(b *elf.Module) error {
mp := b.Map("tcptracer_status")
// pid & tid must not change during the guessing work: the communication
// between ebpf and userspace relies on it
runtime.LockOSThread()
defer runtime.UnlockOSThread()
pidTgid := uint64(os.Getpid())<<32 | uint64(syscall.Gettid())
status := &tcpTracerStatus{
@@ -370,12 +383,18 @@ func guess(b *elf.Module) error {
family: syscall.AF_INET,
}
// if the kretprobe for tcp_v4_connect() is configured with a too-low
// maxactive, some kretprobe might be missing. In this case, we detect
// it and try again.
// See https://github.com/weaveworks/tcptracer-bpf/issues/24
var maxRetries int = 100
for status.state != stateReady {
if err := tryCurrentOffset(b, mp, status, expected, stop); err != nil {
return err
}
if err := checkAndUpdateCurrentOffset(b, mp, status, expected); err != nil {
if err := checkAndUpdateCurrentOffset(b, mp, status, expected, &maxRetries); err != nil {
return err
}

File diff suppressed because one or more lines are too long

View File

@@ -131,7 +131,11 @@ static int are_offsets_ready_v4(struct tcptracer_status_t *status, struct sock *
return 0;
}
if (status->pid_tgid >> 32 != pid >> 32)
// Only accept the exact pid & tid. Extraneous connections from other
// threads must be ignored here. Userland must take care to generate
// connections from the correct thread. In Golang, this can be achieved
// with runtime.LockOSThread.
if (status->pid_tgid != pid)
return 0;
struct tcptracer_status_t new_status = { };
@@ -235,7 +239,11 @@ static int are_offsets_ready_v6(struct tcptracer_status_t *status, struct sock *
return 0;
}
if (status->pid_tgid >> 32 != pid >> 32)
// Only accept the exact pid & tid. Extraneous connections from other
// threads must be ignored here. Userland must take care to generate
// connections from the correct thread. In Golang, this can be achieved
// with runtime.LockOSThread.
if (status->pid_tgid != pid)
return 0;
struct tcptracer_status_t new_status = { };

View File

@@ -47,6 +47,8 @@ func main() {
os.Exit(1)
}
fmt.Printf("Ready\n")
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, os.Kill)

2
vendor/manifest vendored
View File

@@ -1462,7 +1462,7 @@
"importpath": "github.com/weaveworks/tcptracer-bpf",
"repository": "https://github.com/weaveworks/tcptracer-bpf",
"vcs": "git",
"revision": "d4a42f2cc89eb19e60113f7e35945a29b97c695f",
"revision": "5b0b56d81d81cf9739739d347798a04ba1754b2e",
"branch": "master",
"notests": true
},