Sniffer: Exit instantly on unknown ioctls in compatibility enforcement mode.

This makes it easier to deal with client/server-type GPU tests, such as
ollama or vLLM, where the main GPU process is a long-running one. Prior to
this CL, when setting enforcement mode on this process, this would only be
checked if adding explicit code to shut down the container orderly by
sending a signal to the server process, in order to let the ioctl sniffer
have a chance to produce its report. This is easy to miss, because there
is no feedback that would suggest that the ioctl sniffer isn't being
respected in such tests. By exiting instantly as soon as an unsupported
ioctl is found, such code doesn't need to be added.

However, the previous behavior is still useful when testing new
applications, so it is still available as well. The
`--enforce_compatibility` flag is changed to a tri-state flag that can
handle either being turned off, or enforcing compatibility on the spot vs
at exit time.

Updates issue #10885.

PiperOrigin-RevId: 686653876
This commit is contained in:
Etienne Perot
2024-10-16 15:03:45 -07:00
committed by gVisor bot
parent 4cff9027d6
commit d299b3998c
3 changed files with 23 additions and 7 deletions
+3 -2
View File
@@ -187,10 +187,11 @@ func (sgo *SniffGPUOpts) prepend(argv []string) []string {
}
snifferArgv := []string{
ioctlSnifferMountPath,
"--verbose=true",
fmt.Sprintf("--enforce_compatibility=%t", !sgo.AllowIncompatibleIoctl),
// TODO(eperot): Add flag to enforce capability set here once implemented.
}
if !sgo.AllowIncompatibleIoctl {
snifferArgv = append(snifferArgv, "--enforce_compatibility=INSTANT")
}
return append(snifferArgv, argv...)
}
+10 -4
View File
@@ -28,7 +28,7 @@ import (
_ "embed" // Necessary to use go:embed.
)
var enforceCompatability = flag.Bool("enforce_compatibility", false, "If true, the sniffer will fail if it detects an unsupported ioctl.")
var enforceCompatibility = flag.String("enforce_compatibility", "", "May be set to 'INSTANT' or 'REPORT'. If set, the sniffer will return a non-zero error code if it detects an unsupported ioctl. 'INSTANT' causes the sniffer to exit immediately when this happens. 'REPORT' causes the sniffer to report all unsupported ioctls at the end of execution.")
var verbose = flag.Bool("verbose", false, "If true, the sniffer will print all Nvidia ioctls it sees.")
//go:embed libioctl_hook.so
@@ -60,6 +60,10 @@ func Main(ctx context.Context) error {
return fmt.Errorf("no command specified")
}
if *enforceCompatibility != "" && *enforceCompatibility != "INSTANT" && *enforceCompatibility != "REPORT" {
return fmt.Errorf("invalid value for --enforce_compatibility: %q", *enforceCompatibility)
}
if *verbose {
log.SetLevel(log.Debug)
}
@@ -100,8 +104,10 @@ func Main(ctx context.Context) error {
cmd.Stderr = os.Stderr
// Refer to the hook file by file descriptor here as its named file no
// longer exists.
cmd.Env = append(os.Environ(), fmt.Sprintf("LD_PRELOAD=/proc/%d/fd/%d", os.Getpid(), hookFile.Fd()))
cmd.Env = append(cmd.Env, fmt.Sprintf("GVISOR_IOCTL_SNIFFER_SOCKET_PATH=%v", server.Addr()))
cmd.Env = append(os.Environ(),
fmt.Sprintf("LD_PRELOAD=/proc/%d/fd/%d", os.Getpid(), hookFile.Fd()),
fmt.Sprintf("GVISOR_IOCTL_SNIFFER_SOCKET_PATH=%v", server.Addr()),
fmt.Sprintf("GVISOR_IOCTL_SNIFFER_ENFORCE_COMPATIBILITY=%s", *enforceCompatibility))
// Run the command and start reading the output.
if err := cmd.Start(); err != nil {
@@ -115,7 +121,7 @@ func Main(ctx context.Context) error {
// Merge results from each connection.
finalResults := server.AllResults()
if *enforceCompatability && finalResults.HasUnsupportedIoctl() {
if *enforceCompatibility != "" && finalResults.HasUnsupportedIoctl() {
return fmt.Errorf("unsupported ioctls found: %v", finalResults)
}
+10 -1
View File
@@ -20,6 +20,7 @@ import (
"errors"
"fmt"
"io"
"os"
"regexp"
"strings"
@@ -71,7 +72,8 @@ func (c ioctlClass) String() string {
type ioctlSubclass uint32
var (
supportedIoctls [_numClasses]map[uint32]struct{}
supportedIoctls [_numClasses]map[uint32]struct{}
crashOnUnsupportedIoctl bool
)
// Ioctl contains the parsed ioctl protobuf information.
@@ -199,6 +201,9 @@ func Init() error {
alloc: suppAllocClasses,
unknown: make(map[uint32]struct{}),
}
if os.Getenv("GVISOR_IOCTL_SNIFFER_ENFORCE_COMPATIBILITY") == "INSTANT" {
crashOnUnsupportedIoctl = true
}
return nil
}
@@ -226,6 +231,10 @@ func (c Connection) ReadHookOutput(ctx context.Context) *Results {
if !ioctl.IsSupported() {
res.AddUnsupportedIoctl(ioctl)
if crashOnUnsupportedIoctl {
log.Warningf("Unsupported ioctl found; crashing immediately: %v", ioctl)
os.Exit(1)
}
}
}
return res