diff --git a/probe/endpoint/ebpf.go b/probe/endpoint/ebpf.go index 7b4b10fde..ac50fdb94 100644 --- a/probe/endpoint/ebpf.go +++ b/probe/endpoint/ebpf.go @@ -53,16 +53,28 @@ type EbpfTracker struct { closedDuringInit map[fourTuple]struct{} } -var releaseRegex = regexp.MustCompile(`^(\d+)\.(\d+).*$`) +// releaseRegex should match all possible variations of a common Linux +// version string: +// - 4.1 +// - 4.22-foo +// - 4.1.2-foo +// - 4.1.2-33.44+bar +// - etc. +// For example, on a Ubuntu system the vendor specific release part +// (after the first `-`) could look like: +// '.-' or +// '-' +// See https://wiki.ubuntu.com/Kernel/FAQ +var releaseRegex = regexp.MustCompile(`^(\d+)\.(\d+)\.?(\d*)-?(\d*)(.*)$`) func isKernelSupported() error { - release, _, err := host.GetKernelReleaseAndVersion() + release, version, err := host.GetKernelReleaseAndVersion() if err != nil { return err } releaseParts := releaseRegex.FindStringSubmatch(release) - if len(releaseParts) != 3 { + if len(releaseParts) != 6 { return fmt.Errorf("got invalid release version %q (expected format '4.4[.2-1]')", release) } @@ -84,6 +96,24 @@ func isKernelSupported() error { return fmt.Errorf("got kernel %s but need kernel >=4.4", release) } + if strings.Contains(version, "Ubuntu") { + // Check for specific Ubuntu kernel versions with + // known issues. + + abiNumber, err := strconv.Atoi(releaseParts[4]) + if err != nil { + // By now we know it's at least kernel 4.4 and + // not "119-ish", so allow it. + return nil + } + // TODO: give the check an upper limit once the bug is fixed + if major == 4 && minor == 4 && abiNumber >= 119 { + // https://github.com/weaveworks/scope/issues/3131 + // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1763454 + return fmt.Errorf("got Ubuntu kernel %s with known bug", release) + } + } + return nil } diff --git a/probe/endpoint/ebpf_test.go b/probe/endpoint/ebpf_test.go index 1bf182940..98c62116b 100644 --- a/probe/endpoint/ebpf_test.go +++ b/probe/endpoint/ebpf_test.go @@ -8,6 +8,8 @@ import ( "time" "github.com/weaveworks/tcptracer-bpf/pkg/tracer" + + "github.com/weaveworks/scope/probe/host" ) func newMockEbpfTracker() *EbpfTracker { @@ -233,3 +235,74 @@ func TestInvalidTimeStampDead(t *testing.T) { t.Errorf("expected ebpfTracker to be set to dead after events with wrong order") } } + +func TestIsKernelSupported(t *testing.T) { + var release, version string + oldGetKernelReleaseAndVersion := host.GetKernelReleaseAndVersion + defer func() { + host.GetKernelReleaseAndVersion = oldGetKernelReleaseAndVersion + }() + host.GetKernelReleaseAndVersion = func() (string, string, error) { return release, version, nil } + testVersions := []struct { + release string + version string + supported bool + }{ + { + "4.1", + "", + false, + }, + { + "4.4", + "", + true, + }, + { + "4.4-custom", + "", + true, + }, + { + "4.4.127", + "", + true, + }, + { + "4.4.0-119-generic", + "#143-Ubuntu SMP Mon Apr 2 16:08:24 UTC 2018", + false, + }, + { + "4.4.0-116-generic", + "#140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018", + true, + }, + { + "4.13.0-38-generic", + "#43-Ubuntu SMP Wed Mar 14 15:20:44 UTC 2018", + true, + }, + { + "4.13.0-119-generic", + "#43-Ubuntu SMP Wed Apr 1 00:00:00 UTC 2018", + true, + }, + { + "4.9.0-6-amd64", + "#1 SMP Debian 4.9.82-1+deb9u3 (2018-03-02)", + true, + }, + } + for _, tv := range testVersions { + release = tv.release + version = tv.version + err := isKernelSupported() + if tv.supported && err != nil { + t.Errorf("expected kernel release %q version %q to be supported but got error: %v", release, version, err) + } + if !tv.supported && err == nil { + t.Errorf("expected kernel release %q version %q to not be supported", release, version) + } + } +}