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