Use hostos.KernelVersion everywhere, and have it return semver strings

PiperOrigin-RevId: 460872657
This commit is contained in:
Kevin Krakauer
2022-07-13 21:29:08 -07:00
committed by gVisor bot
parent 63bb6e7e69
commit 2ceb6bb1f8
8 changed files with 82 additions and 52 deletions
+3 -3
View File
@@ -22,14 +22,14 @@ import (
) )
func TestEnable(t *testing.T) { func TestEnable(t *testing.T) {
major, minor, err := hostos.KernelVersion() version, err := hostos.KernelVersion()
if err != nil { if err != nil {
t.Fatalf("Unable to parse kernel version: %v", err) t.Fatalf("Unable to parse kernel version: %v", err)
} }
// Skip running test when running on Linux kernel < 5.14 because core tagging // Skip running test when running on Linux kernel < 5.14 because core tagging
// is not available. // is not available.
if major < 5 && minor < 14 { if version.LessThan(5, 14) {
t.Skipf("Running on Linux kernel: %d.%d < 5.14. Core tagging not available. Skipping test.", major, minor) t.Skipf("Running on Linux kernel: %s < 5.14. Core tagging not available. Skipping test.", version)
return return
} }
if err := Enable(); err != nil { if err := Enable(); err != nil {
+10 -8
View File
@@ -17,38 +17,40 @@
package cpuid package cpuid
func archSkipFeature(feature Feature, major, minor int) bool { import "gvisor.dev/gvisor/pkg/hostos"
func archSkipFeature(feature Feature, version hostos.Version) bool {
switch { switch {
// Block 0. // Block 0.
case feature == X86FeatureSDBG && (major < 4 || major == 4 && minor < 3): case feature == X86FeatureSDBG && version.AtLeast(4, 3):
// SDBG only exposed in // SDBG only exposed in
// b1c599b8ff80ea79b9f8277a3f9f36a7b0cfedce (4.3). // b1c599b8ff80ea79b9f8277a3f9f36a7b0cfedce (4.3).
return true return true
// Block 2. // Block 2.
case feature == X86FeatureRDT && (major < 4 || major == 4 && minor < 10): case feature == X86FeatureRDT && version.AtLeast(4, 10):
// RDT only exposed in // RDT only exposed in
// 4ab1586488cb56ed8728e54c4157cc38646874d9 (4.10). // 4ab1586488cb56ed8728e54c4157cc38646874d9 (4.10).
return true return true
// Block 3. // Block 3.
case feature == X86FeatureAVX512VBMI && (major < 4 || major == 4 && minor < 10): case feature == X86FeatureAVX512VBMI && version.AtLeast(4, 10):
// AVX512VBMI only exposed in // AVX512VBMI only exposed in
// a8d9df5a509a232a959e4ef2e281f7ecd77810d6 (4.10). // a8d9df5a509a232a959e4ef2e281f7ecd77810d6 (4.10).
return true return true
case feature == X86FeatureUMIP && (major < 4 || major == 4 && minor < 15): case feature == X86FeatureUMIP && version.AtLeast(4, 15):
// UMIP only exposed in // UMIP only exposed in
// 3522c2a6a4f341058b8291326a945e2a2d2aaf55 (4.15). // 3522c2a6a4f341058b8291326a945e2a2d2aaf55 (4.15).
return true return true
case feature == X86FeaturePKU && (major < 4 || major == 4 && minor < 9): case feature == X86FeaturePKU && version.AtLeast(4, 9):
// PKU only exposed in // PKU only exposed in
// dfb4a70f20c5b3880da56ee4c9484bdb4e8f1e65 (4.9). // dfb4a70f20c5b3880da56ee4c9484bdb4e8f1e65 (4.9).
return true return true
// Block 4. // Block 4.
case feature == X86FeatureXSAVES && (major < 4 || major == 4 && minor < 8): case feature == X86FeatureXSAVES && version.AtLeast(4, 8):
// XSAVES only exposed in // XSAVES only exposed in
// b8be15d588060a03569ac85dc4a0247460988f5b (4.8). // b8be15d588060a03569ac85dc4a0247460988f5b (4.8).
return true return true
// Block 5. // Block 5.
case feature == X86FeaturePERFCTR_LLC && (major < 4 || major == 4 && minor < 14): case feature == X86FeaturePERFCTR_LLC && version.AtLeast(4, 14):
// PERFCTR_LLC renamed in // PERFCTR_LLC renamed in
// 910448bbed066ab1082b510eef1ae61bb792d854 (4.14). // 910448bbed066ab1082b510eef1ae61bb792d854 (4.14).
return true return true
+1 -1
View File
@@ -17,6 +17,6 @@
package cpuid package cpuid
func archSkipFeature(feature Feature, major, minor int) bool { func archSkipFeature(feature Feature, version hostos.Version) bool {
return false return false
} }
+2 -2
View File
@@ -31,7 +31,7 @@ import (
// analog in the actual CPUID feature set. // analog in the actual CPUID feature set.
func TestHostFeatureFlags(t *testing.T) { func TestHostFeatureFlags(t *testing.T) {
// Extract the kernel version. // Extract the kernel version.
major, minor, err := hostos.KernelVersion() version, err := hostos.KernelVersion()
if err != nil { if err != nil {
t.Fatalf("Unable to parse kernel version: %v", err) t.Fatalf("Unable to parse kernel version: %v", err)
} }
@@ -54,7 +54,7 @@ func TestHostFeatureFlags(t *testing.T) {
for feature, info := range allFeatures { for feature, info := range allFeatures {
// Special cases not consistently visible. We don't mind if // Special cases not consistently visible. We don't mind if
// they are exposed in earlier versions. // they are exposed in earlier versions.
if archSkipFeature(feature, major, minor) { if archSkipFeature(feature, version) {
continue continue
} }
+4 -1
View File
@@ -6,5 +6,8 @@ go_library(
name = "hostos", name = "hostos",
srcs = ["hostos.go"], srcs = ["hostos.go"],
visibility = ["//:sandbox"], visibility = ["//:sandbox"],
deps = ["@org_golang_x_sys//unix:go_default_library"], deps = [
"@org_golang_x_mod//semver:go_default_library",
"@org_golang_x_sys//unix:go_default_library",
],
) )
+56 -26
View File
@@ -17,41 +17,71 @@ package hostos
import ( import (
"fmt" "fmt"
"strconv" "regexp"
"strings" "strings"
"sync"
"golang.org/x/mod/semver"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
// KernelVersion returns the major and minor release version of the kernel using uname(). // Version represents a semantic version of the form "%d.%d[.%d]".
func KernelVersion() (int, int, error) { type Version struct {
var u unix.Utsname version string
if err := unix.Uname(&u); err != nil { }
return 0, 0, err
// AtLeast returns whether vr is at least version major.minor.
func (vr Version) AtLeast(major, minor int) bool {
return semver.Compare(vr.version, fmt.Sprintf("v%d.%d", major, minor)) >= 0
}
// LessThan returns whether vr is less than version major.minor.
func (vr Version) LessThan(major, minor int) bool {
return !vr.AtLeast(major, minor)
}
// String implements fmt.Stringer.
func (vr Version) String() string {
if vr.version == "" {
return "unknown"
} }
// Omit the "v" prefix required by semver.
return vr.version[1:]
}
var sb strings.Builder // These values are effectively local to KernelVersion, but kept here so as to
for _, b := range u.Release { // work with sync.Once.
if b == 0 { var (
break semVersion Version
unameErr error
once sync.Once
)
// KernelVersion returns the version of the kernel using uname().
func KernelVersion() (Version, error) {
once.Do(func() {
var utsname unix.Utsname
if err := unix.Uname(&utsname); err != nil {
unameErr = err
return
} }
sb.WriteByte(byte(b))
}
s := strings.Split(sb.String(), ".") var sb strings.Builder
if len(s) < 2 { for _, b := range utsname.Release {
return 0, 0, fmt.Errorf("kernel release missing major and minor component: %s", sb.String()) if b == 0 {
} break
}
sb.WriteByte(byte(b))
}
major, err := strconv.Atoi(s[0]) versionRegexp := regexp.MustCompile(`[0-9]+\.[0-9]+(\.[0-9]+)?`)
if err != nil { version := "v" + string(versionRegexp.Find([]byte(sb.String())))
return 0, 0, fmt.Errorf("error parsing major version %q in %q: %w", s[0], sb.String(), err) if !semver.IsValid(version) {
} unameErr = fmt.Errorf("invalid version found in release %q", sb.String())
return
minor, err := strconv.Atoi(s[1]) }
if err != nil { semVersion.version = version
return 0, 0, fmt.Errorf("error parsing minor version %q in %q: %w", s[1], sb.String(), err) })
}
return major, minor, nil return semVersion, unameErr
} }
+1 -1
View File
@@ -40,6 +40,7 @@ go_library(
"//pkg/fd", "//pkg/fd",
"//pkg/flipcall", "//pkg/flipcall",
"//pkg/fspath", "//pkg/fspath",
"//pkg/hostos",
"//pkg/log", "//pkg/log",
"//pkg/memutil", "//pkg/memutil",
"//pkg/rand", "//pkg/rand",
@@ -119,7 +120,6 @@ go_library(
"//runsc/specutils/seccomp", "//runsc/specutils/seccomp",
"@com_github_opencontainers_runtime_spec//specs-go:go_default_library", "@com_github_opencontainers_runtime_spec//specs-go:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library", "@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_x_mod//semver:go_default_library",
"@org_golang_x_sys//unix:go_default_library", "@org_golang_x_sys//unix:go_default_library",
], ],
) )
+5 -10
View File
@@ -17,12 +17,11 @@ package boot
import ( import (
"fmt" "fmt"
"net" "net"
"regexp"
"runtime" "runtime"
"strings" "strings"
"golang.org/x/mod/semver"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/hostos"
"gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/link/ethernet" "gvisor.dev/gvisor/pkg/tcpip/link/ethernet"
@@ -197,16 +196,12 @@ func (n *Network) CreateLinksAndRoutes(args *CreateLinksAndRoutesArgs, _ *struct
} }
// Choose a dispatch mode. // Choose a dispatch mode.
// Get the Linux kernel version. Uname will return something like dispatchMode := fdbased.RecvMMsg
// "5.17.7-1distro-amd64", from which we'd want "5.17.7". version, err := hostos.KernelVersion()
var uname unix.Utsname if err != nil {
if err := unix.Uname(&uname); err != nil {
return err return err
} }
re := regexp.MustCompile(`[0-9]+\.[0-9]+(\.[0-9]+)?`) if version.AtLeast(5, 6) {
version := "v" + string(re.Find(uname.Release[:]))
dispatchMode := fdbased.RecvMMsg
if semver.IsValid(version) && semver.Compare(version, "v5.6") >= 0 {
dispatchMode = fdbased.PacketMMap dispatchMode = fdbased.PacketMMap
} else { } else {
log.Infof("Host kernel version < 5.6, falling back to RecvMMsg dispatch") log.Infof("Host kernel version < 5.6, falling back to RecvMMsg dispatch")