Skip to content

Commit 0407777

Browse files
committed
Merge pull request #11498 from tianyuzhou95:albert/cpuid
PiperOrigin-RevId: 794363944
2 parents 3bb8974 + f3900b2 commit 0407777

File tree

7 files changed

+116
-1
lines changed

7 files changed

+116
-1
lines changed

pkg/cpuid/native_amd64.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,23 @@ func (fs FeatureSet) query(fn cpuidFunction) (uint32, uint32, uint32, uint32) {
163163
return out.Eax, out.Ebx, out.Ecx, out.Edx
164164
}
165165

166+
// Intersect returns the intersection of features between self and allowedFeatures.
167+
func (fs FeatureSet) Intersect(allowedFeatures map[Feature]struct{}) (FeatureSet, error) {
168+
hs := fs.ToStatic()
169+
170+
// only keep features inside allowedFeatures.
171+
for f := range allFeatures {
172+
if fs.HasFeature(f) {
173+
if _, ok := allowedFeatures[f]; !ok {
174+
log.Infof("Removing CPU feature %v as it is not allowed.", f)
175+
hs.Remove(f)
176+
}
177+
}
178+
}
179+
180+
return hs.ToFeatureSet(), nil
181+
}
182+
166183
var hostFeatureSet FeatureSet
167184

168185
// HostFeatureSet returns a host CPUID.

pkg/cpuid/native_arm64.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package cpuid
1919

2020
import (
21+
"fmt"
2122
"os"
2223
"runtime"
2324
"strconv"
@@ -41,6 +42,13 @@ func (fs FeatureSet) Fixed() FeatureSet {
4142
return fs
4243
}
4344

45+
// Intersect returns the intersection of features between self and allowedFeatures.
46+
//
47+
// Just return error as there is no ARM64 equivalent to cpuid.Static.Remove().
48+
func (fs FeatureSet) Intersect(allowedFeatures map[Feature]struct{}) (FeatureSet, error) {
49+
return FeatureSet{}, fmt.Errorf("FeatureSet intersection is not supported on ARM64")
50+
}
51+
4452
// Reads CPU information from host /proc/cpuinfo.
4553
//
4654
// Must run before syscall filter installation. This value is used to create

runsc/boot/loader.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"os"
2222
"runtime"
2323
"strconv"
24+
"strings"
2425
gtime "time"
2526

2627
"github.com/moby/sys/capability"
@@ -597,6 +598,26 @@ func New(args Args) (*Loader, error) {
597598
log.Infof("Setting total memory to %.2f GB", float64(args.TotalMem)/(1<<30))
598599
}
599600

601+
cpufs := cpuid.HostFeatureSet()
602+
if value, ok := args.Spec.Annotations[specutils.AnnotationCPUFeatures]; ok {
603+
allowedFeatures := make(map[cpuid.Feature]struct{})
604+
for str := range strings.SplitSeq(value, ",") {
605+
if str == "" {
606+
continue // ignore empty feature name rather than return error
607+
}
608+
f, ok := cpuid.FeatureFromString(str)
609+
if !ok {
610+
return nil, fmt.Errorf("annotation %s contains unknown feature %s", specutils.AnnotationCPUFeatures, str)
611+
}
612+
allowedFeatures[f] = struct{}{}
613+
}
614+
afs, err := cpufs.Intersect(allowedFeatures) // err only needed for now because this isn't implemented on ARM64 yet
615+
if err != nil {
616+
return nil, err
617+
}
618+
cpufs = afs
619+
}
620+
600621
maxFDLimit := kernel.MaxFdLimit
601622
if args.Spec.Linux != nil && args.Spec.Linux.Sysctl != nil {
602623
if val, ok := args.Spec.Linux.Sysctl["fs.nr_open"]; ok {
@@ -616,7 +637,7 @@ func New(args Args) (*Loader, error) {
616637
DisconnectOnSave: args.Conf.NetDisconnectOk,
617638
}
618639
if err = l.k.Init(kernel.InitKernelArgs{
619-
FeatureSet: cpuid.HostFeatureSet().Fixed(),
640+
FeatureSet: cpufs.Fixed(),
620641
Timekeeper: tk,
621642
RootUserNamespace: creds.UserNamespace,
622643
RootNetworkNamespace: netns,

runsc/cli/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ func forEachCmd(cb func(cmd subcommands.Command, group string)) {
281281
cb(new(cmd.Uninstall), helperGroup)
282282
cb(new(nvproxy.Nvproxy), helperGroup)
283283
cb(new(trace.Trace), helperGroup)
284+
cb(new(cmd.CPUFeatures), helperGroup)
284285

285286
const debugGroup = "debug"
286287
cb(new(cmd.Debug), debugGroup)

runsc/cmd/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ go_library(
3838
"checkpoint.go",
3939
"chroot.go",
4040
"cmd.go",
41+
"cpu_features.go",
4142
"create.go",
4243
"debug.go",
4344
"delete.go",

runsc/cmd/cpu_features.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2025 The gVisor Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cmd
16+
17+
import (
18+
"context"
19+
"fmt"
20+
"strings"
21+
22+
"github.com/google/subcommands"
23+
"gvisor.dev/gvisor/pkg/cpuid"
24+
"gvisor.dev/gvisor/runsc/flag"
25+
)
26+
27+
// CPUFeatures implements subcommands.Command for the "cpu-features" command.
28+
type CPUFeatures struct{}
29+
30+
// Name implements subcommands.command.name.
31+
func (*CPUFeatures) Name() string {
32+
return "cpu-features"
33+
}
34+
35+
// Synopsis implements subcommands.Command.Synopsis.
36+
func (*CPUFeatures) Synopsis() string {
37+
return "list CPU features supported on current machine"
38+
}
39+
40+
// Usage implements subcommands.Command.Usage.
41+
func (*CPUFeatures) Usage() string {
42+
return "cpu-features\n"
43+
}
44+
45+
// SetFlags implements subcommands.Command.SetFlags.
46+
func (*CPUFeatures) SetFlags(*flag.FlagSet) {}
47+
48+
// Execute implements subcommands.Command.Execute.
49+
func (*CPUFeatures) Execute(_ context.Context, _ *flag.FlagSet, args ...any) subcommands.ExitStatus {
50+
cpuid.Initialize()
51+
hfs := cpuid.HostFeatureSet().Fixed()
52+
allFeatures := cpuid.AllFeatures()
53+
54+
features := []string{}
55+
for _, v := range allFeatures {
56+
if hfs.HasFeature(v) {
57+
features = append(features, v.String())
58+
}
59+
}
60+
fmt.Println(strings.Join(features, ","))
61+
62+
return subcommands.ExitSuccess
63+
}

runsc/specutils/specutils.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ const (
7070

7171
// AnnotationTPU is the annotation used to enable TPU proxy on a pod.
7272
AnnotationTPU = "dev.gvisor.internal.tpuproxy"
73+
74+
// AnnotationCPUFeatures is the annotation used to control cpu features
75+
// that exposed to user apps.
76+
AnnotationCPUFeatures = "dev.gvisor.internal.cpufeatures"
7377
)
7478

7579
// ExePath must point to runsc binary, which is normally the same binary. It's

0 commit comments

Comments
 (0)