github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/runsc/config/config.go (about)

     1  // Copyright 2020 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 config provides basic infrastructure to set configuration settings
    16  // for runsc. The configuration is set by flags to the command line. They can
    17  // also propagate to a different process using the same flags.
    18  package config
    19  
    20  import (
    21  	"fmt"
    22  	"path/filepath"
    23  	"runtime"
    24  	"strconv"
    25  	"strings"
    26  	"time"
    27  
    28  	"github.com/MerlinKodo/gvisor/pkg/refs"
    29  	"github.com/MerlinKodo/gvisor/pkg/sentry/watchdog"
    30  	"github.com/MerlinKodo/gvisor/runsc/flag"
    31  	"github.com/MerlinKodo/gvisor/runsc/version"
    32  )
    33  
    34  // Config holds configuration that is not part of the runtime spec.
    35  //
    36  // Follow these steps to add a new flag:
    37  //  1. Create a new field in Config.
    38  //  2. Add a field tag with the flag name
    39  //  3. Register a new flag in flags.go, with same name and add a description
    40  //  4. Add any necessary validation into validate()
    41  //  5. If adding an enum, follow the same pattern as FileAccessType
    42  //  6. Evaluate if the flag can be changed with OCI annotations. See
    43  //     overrideAllowlist for more details
    44  type Config struct {
    45  	// RootDir is the runtime root directory.
    46  	RootDir string `flag:"root"`
    47  
    48  	// Traceback changes the Go runtime's traceback level.
    49  	Traceback string `flag:"traceback"`
    50  
    51  	// Debug indicates that debug logging should be enabled.
    52  	Debug bool `flag:"debug"`
    53  
    54  	// LogFilename is the filename to log to, if not empty.
    55  	LogFilename string `flag:"log"`
    56  
    57  	// LogFormat is the log format.
    58  	LogFormat string `flag:"log-format"`
    59  
    60  	// DebugLog is the path to log debug information to, if not empty.
    61  	DebugLog string `flag:"debug-log"`
    62  
    63  	// DebugCommand is a comma-separated list of commands to be debugged if
    64  	// --debug-log is also set. Empty means debug all. "!" negates the expression.
    65  	// E.g. "create,start" or "!boot,events".
    66  	DebugCommand string `flag:"debug-command"`
    67  
    68  	// PanicLog is the path to log GO's runtime messages, if not empty.
    69  	PanicLog string `flag:"panic-log"`
    70  
    71  	// CoverageReport is the path to write Go coverage information, if not empty.
    72  	CoverageReport string `flag:"coverage-report"`
    73  
    74  	// DebugLogFormat is the log format for debug.
    75  	DebugLogFormat string `flag:"debug-log-format"`
    76  
    77  	// FileAccess indicates how the root filesystem is accessed.
    78  	FileAccess FileAccessType `flag:"file-access"`
    79  
    80  	// FileAccessMounts indicates how non-root volumes are accessed.
    81  	FileAccessMounts FileAccessType `flag:"file-access-mounts"`
    82  
    83  	// Overlay is whether to wrap all mounts in an overlay. The upper tmpfs layer
    84  	// will be backed by application memory.
    85  	Overlay bool `flag:"overlay"`
    86  
    87  	// Overlay2 holds configuration about wrapping mounts in overlayfs.
    88  	// DO NOT call it directly, use GetOverlay2() instead.
    89  	Overlay2 Overlay2 `flag:"overlay2"`
    90  
    91  	// FSGoferHostUDS is deprecated: use host-uds=all.
    92  	FSGoferHostUDS bool `flag:"fsgofer-host-uds"`
    93  
    94  	// HostUDS controls permission to access host Unix-domain sockets.
    95  	// DO NOT call it directly, use GetHostUDS() instead.
    96  	HostUDS HostUDS `flag:"host-uds"`
    97  
    98  	// HostFifo controls permission to access host FIFO (or named pipes).
    99  	HostFifo HostFifo `flag:"host-fifo"`
   100  
   101  	// Network indicates what type of network to use.
   102  	Network NetworkType `flag:"network"`
   103  
   104  	// EnableRaw indicates whether raw sockets should be enabled. Raw
   105  	// sockets are disabled by stripping CAP_NET_RAW from the list of
   106  	// capabilities.
   107  	EnableRaw bool `flag:"net-raw"`
   108  
   109  	// AllowPacketEndpointWrite enables write operations on packet endpoints.
   110  	AllowPacketEndpointWrite bool `flag:"TESTONLY-allow-packet-endpoint-write"`
   111  
   112  	// HostGSO indicates that host segmentation offload is enabled.
   113  	HostGSO bool `flag:"gso"`
   114  
   115  	// GvisorGSO indicates that gVisor segmentation offload is enabled. The flag
   116  	// retains its old name of "software" GSO for API consistency.
   117  	GvisorGSO bool `flag:"software-gso"`
   118  
   119  	// GvisorGROTimeout sets gVisor's generic receive offload timeout. Zero
   120  	// bypasses GRO.
   121  	GvisorGROTimeout time.Duration `flag:"gvisor-gro"`
   122  
   123  	// TXChecksumOffload indicates that TX Checksum Offload is enabled.
   124  	TXChecksumOffload bool `flag:"tx-checksum-offload"`
   125  
   126  	// RXChecksumOffload indicates that RX Checksum Offload is enabled.
   127  	RXChecksumOffload bool `flag:"rx-checksum-offload"`
   128  
   129  	// QDisc indicates the type of queuening discipline to use by default
   130  	// for non-loopback interfaces.
   131  	QDisc QueueingDiscipline `flag:"qdisc"`
   132  
   133  	// LogPackets indicates that all network packets should be logged.
   134  	LogPackets bool `flag:"log-packets"`
   135  
   136  	// PCAP is a file to which network packets should be logged in PCAP format.
   137  	PCAP string `flag:"pcap-log"`
   138  
   139  	// Platform is the platform to run on.
   140  	Platform string `flag:"platform"`
   141  
   142  	// PlatformDevicePath is the path to the device file used by the platform.
   143  	// e.g. "/dev/kvm" for the KVM platform.
   144  	// If unset, a sane platform-specific default will be used.
   145  	PlatformDevicePath string `flag:"platform_device_path"`
   146  
   147  	// MetricServer, if set, indicates that metrics should be exported on this address.
   148  	// This may either be 1) "addr:port" to export metrics on a specific network interface address,
   149  	// 2) ":port" for exporting metrics on all addresses, or 3) an absolute path to a Unix Domain
   150  	// Socket.
   151  	// The substring "%ID%" will be replaced by the container ID, and "%RUNTIME_ROOT%" by the root.
   152  	// This flag must be specified *both* as part of the `runsc metric-server` arguments (so that the
   153  	// metric server knows which address to bind to), and as part of the `runsc create` arguments (as
   154  	// an indication that the container being created wishes that its metrics should be exported).
   155  	// The value of this flag must also match across the two command lines.
   156  	MetricServer string `flag:"metric-server"`
   157  
   158  	// ProfilingMetrics is a comma separated list of metric names which are
   159  	// going to be written to the ProfilingMetricsLog file from within the
   160  	// sentry in CSV format. ProfilingMetrics will be snapshotted at a rate
   161  	// specified by ProfilingMetricsRate. Requires ProfilingMetricsLog to be
   162  	// set.
   163  	ProfilingMetrics string `flag:"profiling-metrics"`
   164  
   165  	// ProfilingMetricsLog is the file name to use for ProfilingMetrics
   166  	// output.
   167  	ProfilingMetricsLog string `flag:"profiling-metrics-log"`
   168  
   169  	// ProfilingMetricsRate is the target rate (in microseconds) at which
   170  	// profiling metrics will be snapshotted.
   171  	ProfilingMetricsRate int `flag:"profiling-metrics-rate-us"`
   172  
   173  	// Strace indicates that strace should be enabled.
   174  	Strace bool `flag:"strace"`
   175  
   176  	// StraceSyscalls is the set of syscalls to trace (comma-separated values).
   177  	// If StraceEnable is true and this string is empty, then all syscalls will
   178  	// be traced.
   179  	StraceSyscalls string `flag:"strace-syscalls"`
   180  
   181  	// StraceLogSize is the max size of data blobs to display.
   182  	StraceLogSize uint `flag:"strace-log-size"`
   183  
   184  	// StraceEvent indicates sending strace to events if true. Strace is
   185  	// sent to log if false.
   186  	StraceEvent bool `flag:"strace-event"`
   187  
   188  	// DisableSeccomp indicates whether seccomp syscall filters should be
   189  	// disabled. Pardon the double negation, but default to enabled is important.
   190  	DisableSeccomp bool
   191  
   192  	// EnableCoreTags indicates whether the Sentry process and children will be
   193  	// run in a core tagged process. This isolates the sentry from sharing
   194  	// physical cores with other core tagged processes. This is useful as a
   195  	// mitigation for hyperthreading side channel based attacks. Requires host
   196  	// linux kernel >= 5.14.
   197  	EnableCoreTags bool `flag:"enable-core-tags"`
   198  
   199  	// WatchdogAction sets what action the watchdog takes when triggered.
   200  	WatchdogAction watchdog.Action `flag:"watchdog-action"`
   201  
   202  	// PanicSignal registers signal handling that panics. Usually set to
   203  	// SIGUSR2(12) to troubleshoot hangs. -1 disables it.
   204  	PanicSignal int `flag:"panic-signal"`
   205  
   206  	// ProfileEnable is set to prepare the sandbox to be profiled.
   207  	ProfileEnable bool `flag:"profile"`
   208  
   209  	// ProfileBlock collects a block profile to the passed file for the
   210  	// duration of the container execution. Requires ProfileEnabled.
   211  	ProfileBlock string `flag:"profile-block"`
   212  
   213  	// ProfileCPU collects a CPU profile to the passed file for the
   214  	// duration of the container execution. Requires ProfileEnabled.
   215  	ProfileCPU string `flag:"profile-cpu"`
   216  
   217  	// ProfileHeap collects a heap profile to the passed file for the
   218  	// duration of the container execution. Requires ProfileEnabled.
   219  	ProfileHeap string `flag:"profile-heap"`
   220  
   221  	// ProfileMutex collects a mutex profile to the passed file for the
   222  	// duration of the container execution. Requires ProfileEnabled.
   223  	ProfileMutex string `flag:"profile-mutex"`
   224  
   225  	// TraceFile collects a Go runtime execution trace to the passed file
   226  	// for the duration of the container execution.
   227  	TraceFile string `flag:"trace"`
   228  
   229  	// RestoreFile is the path to the saved container image.
   230  	RestoreFile string
   231  
   232  	// NumNetworkChannels controls the number of AF_PACKET sockets that map
   233  	// to the same underlying network device. This allows netstack to better
   234  	// scale for high throughput use cases.
   235  	NumNetworkChannels int `flag:"num-network-channels"`
   236  
   237  	// Rootless allows the sandbox to be started with a user that is not root.
   238  	// Defense in depth measures are weaker in rootless mode. Specifically, the
   239  	// sandbox and Gofer process run as root inside a user namespace with root
   240  	// mapped to the caller's user. When using rootless, the container root path
   241  	// should not have a symlink.
   242  	Rootless bool `flag:"rootless"`
   243  
   244  	// AlsoLogToStderr allows to send log messages to stderr.
   245  	AlsoLogToStderr bool `flag:"alsologtostderr"`
   246  
   247  	// ReferenceLeakMode sets reference leak check mode
   248  	ReferenceLeak refs.LeakMode `flag:"ref-leak-mode"`
   249  
   250  	// CPUNumFromQuota sets CPU number count to available CPU quota, using
   251  	// least integer value greater than or equal to quota.
   252  	//
   253  	// E.g. 0.2 CPU quota will result in 1, and 1.9 in 2.
   254  	CPUNumFromQuota bool `flag:"cpu-num-from-quota"`
   255  
   256  	// Allows overriding of flags in OCI annotations.
   257  	AllowFlagOverride bool `flag:"allow-flag-override"`
   258  
   259  	// Enables seccomp inside the sandbox.
   260  	OCISeccomp bool `flag:"oci-seccomp"`
   261  
   262  	// Mounts the cgroup filesystem backed by the sentry's cgroupfs.
   263  	Cgroupfs bool `flag:"cgroupfs"`
   264  
   265  	// Don't configure cgroups.
   266  	IgnoreCgroups bool `flag:"ignore-cgroups"`
   267  
   268  	// Use systemd to configure cgroups.
   269  	SystemdCgroup bool `flag:"systemd-cgroup"`
   270  
   271  	// PodInitConfig is the path to configuration file with additional steps to
   272  	// take during pod creation.
   273  	PodInitConfig string `flag:"pod-init-config"`
   274  
   275  	// Use pools to manage buffer memory instead of heap.
   276  	BufferPooling bool `flag:"buffer-pooling"`
   277  
   278  	// AFXDP defines whether to use an AF_XDP socket to receive packets
   279  	// (rather than AF_PACKET). Enabling it disables RX checksum offload.
   280  	AFXDP bool `flag:"EXPERIMENTAL-afxdp"`
   281  
   282  	// FDLimit specifies a limit on the number of host file descriptors that can
   283  	// be open simultaneously by the sentry and gofer. It applies separately to
   284  	// each.
   285  	FDLimit int `flag:"fdlimit"`
   286  
   287  	// DCache sets the global dirent cache size. If zero, per-mount caches are
   288  	// used.
   289  	DCache int `flag:"dcache"`
   290  
   291  	// IOUring enables support for the IO_URING API calls to perform
   292  	// asynchronous I/O operations.
   293  	IOUring bool `flag:"iouring"`
   294  
   295  	// DirectFS sets up the sandbox to directly access/mutate the filesystem from
   296  	// the sentry. Sentry runs with escalated privileges. Gofer process still
   297  	// exists, but is mostly idle. Not supported in rootless mode.
   298  	DirectFS bool `flag:"directfs"`
   299  
   300  	// NVProxy enables support for Nvidia GPUs.
   301  	NVProxy bool `flag:"nvproxy"`
   302  
   303  	// NVProxyDocker exposes GPUs to containers based on the
   304  	// NVIDIA_VISIBLE_DEVICES container environment variable, as requested by
   305  	// containers or set by `docker --gpus`.
   306  	NVProxyDocker bool `flag:"nvproxy-docker"`
   307  
   308  	// TPUProxy enables support for TPUs.
   309  	TPUProxy bool `flag:"tpuproxy"`
   310  
   311  	// TestOnlyAllowRunAsCurrentUserWithoutChroot should only be used in
   312  	// tests. It allows runsc to start the sandbox process as the current
   313  	// user, and without chrooting the sandbox process. This can be
   314  	// necessary in test environments that have limited capabilities. When
   315  	// disabling chroot, the container root path should not have a symlink.
   316  	TestOnlyAllowRunAsCurrentUserWithoutChroot bool `flag:"TESTONLY-unsafe-nonroot"`
   317  
   318  	// TestOnlyTestNameEnv should only be used in tests. It looks up for the
   319  	// test name in the container environment variables and adds it to the debug
   320  	// log file name. This is done to help identify the log with the test when
   321  	// multiple tests are run in parallel, since there is no way to pass
   322  	// parameters to the runtime from docker.
   323  	TestOnlyTestNameEnv string `flag:"TESTONLY-test-name-env"`
   324  
   325  	// TestOnlyAFSSyscallPanic should only be used in tests. It enables the
   326  	// alternate behaviour for afs_syscall to trigger a Go-runtime panic upon being
   327  	// called. This is useful for tests exercising gVisor panic-reporting.
   328  	TestOnlyAFSSyscallPanic bool `flag:"TESTONLY-afs-syscall-panic"`
   329  
   330  	// explicitlySet contains whether a flag was explicitly set on the command-line from which this
   331  	// Config was constructed. Nil when the Config was not initialized from a FlagSet.
   332  	explicitlySet map[string]struct{}
   333  }
   334  
   335  func (c *Config) validate() error {
   336  	if c.Overlay && c.Overlay2.Enabled() {
   337  		// Deprecated flag was used together with flag that replaced it.
   338  		return fmt.Errorf("overlay flag has been replaced with overlay2 flag")
   339  	}
   340  	if overlay2 := c.GetOverlay2(); c.FileAccess == FileAccessShared && overlay2.Enabled() {
   341  		return fmt.Errorf("overlay flag is incompatible with shared file access for rootfs")
   342  	}
   343  	if c.NumNetworkChannels <= 0 {
   344  		return fmt.Errorf("num_network_channels must be > 0, got: %d", c.NumNetworkChannels)
   345  	}
   346  	// Require profile flags to explicitly opt-in to profiling with
   347  	// -profile rather than implying it since these options have security
   348  	// implications.
   349  	if c.ProfileBlock != "" && !c.ProfileEnable {
   350  		return fmt.Errorf("profile-block flag requires enabling profiling with profile flag")
   351  	}
   352  	if c.ProfileCPU != "" && !c.ProfileEnable {
   353  		return fmt.Errorf("profile-cpu flag requires enabling profiling with profile flag")
   354  	}
   355  	if c.ProfileHeap != "" && !c.ProfileEnable {
   356  		return fmt.Errorf("profile-heap flag requires enabling profiling with profile flag")
   357  	}
   358  	if c.ProfileMutex != "" && !c.ProfileEnable {
   359  		return fmt.Errorf("profile-mutex flag requires enabling profiling with profile flag")
   360  	}
   361  	if c.FSGoferHostUDS && c.HostUDS != HostUDSNone {
   362  		// Deprecated flag was used together with flag that replaced it.
   363  		return fmt.Errorf("fsgofer-host-uds has been replaced with host-uds flag")
   364  	}
   365  	if len(c.ProfilingMetrics) > 0 && len(c.ProfilingMetricsLog) == 0 {
   366  		return fmt.Errorf("profiling-metrics flag requires defining a profiling-metrics-log for output")
   367  	}
   368  	return nil
   369  }
   370  
   371  // GetHostUDS returns the FS gofer communication that is allowed, taking into
   372  // consideration all flags what affect the result.
   373  func (c *Config) GetHostUDS() HostUDS {
   374  	if c.FSGoferHostUDS {
   375  		if c.HostUDS != HostUDSNone {
   376  			panic(fmt.Sprintf("HostUDS cannot be set when --fsgofer-host-uds=true"))
   377  		}
   378  		// Using deprecated flag, honor it to avoid breaking users.
   379  		return HostUDSOpen
   380  	}
   381  	return c.HostUDS
   382  }
   383  
   384  // GetOverlay2 returns the overlay configuration, taking into consideration all
   385  // flags that affect the result.
   386  func (c *Config) GetOverlay2() Overlay2 {
   387  	if c.Overlay {
   388  		if c.Overlay2.Enabled() {
   389  			panic(fmt.Sprintf("Overlay2 cannot be set when --overlay=true"))
   390  		}
   391  		// Using a deprecated flag, honor it to avoid breaking users.
   392  		return Overlay2{rootMount: true, subMounts: true, medium: "memory"}
   393  	}
   394  	return c.Overlay2
   395  }
   396  
   397  // Bundle is a set of flag name-value pairs.
   398  type Bundle map[string]string
   399  
   400  // BundleName is a human-friendly name for a Bundle.
   401  // It is used as part of an annotation to specify that the user wants to apply a Bundle.
   402  type BundleName string
   403  
   404  // Validate validates that given flag string values map to actual flags in runsc.
   405  func (b Bundle) Validate() error {
   406  	flagSet := flag.NewFlagSet("tmp", flag.ContinueOnError)
   407  	RegisterFlags(flagSet)
   408  	for key, val := range b {
   409  		flag := flagSet.Lookup(key)
   410  		if flag == nil {
   411  			return fmt.Errorf("unknown flag %q", key)
   412  		}
   413  		if err := flagSet.Set(key, val); err != nil {
   414  			return err
   415  		}
   416  	}
   417  	return nil
   418  }
   419  
   420  // MetricMetadataKeys is the set of keys of metric metadata labels
   421  // as returned by `Config.MetricMetadata`.
   422  var MetricMetadataKeys = []string{
   423  	"version",
   424  	"platform",
   425  	"network",
   426  	"numcores",
   427  	"coretags",
   428  	"overlay",
   429  	"fsmode",
   430  	"cpuarch",
   431  	"go",
   432  	"experiment",
   433  }
   434  
   435  // MetricMetadata returns key-value pairs that are useful to include in metrics
   436  // exported about the sandbox this config represents.
   437  // It must return the same set of labels as listed in `MetricMetadataKeys`.
   438  func (c *Config) MetricMetadata() map[string]string {
   439  	var fsMode = "goferfs"
   440  	if c.DirectFS {
   441  		fsMode = "directfs"
   442  	}
   443  	return map[string]string{
   444  		"version":  version.Version(),
   445  		"platform": c.Platform,
   446  		"network":  c.Network.String(),
   447  		"numcores": strconv.Itoa(runtime.NumCPU()),
   448  		"coretags": strconv.FormatBool(c.EnableCoreTags),
   449  		"overlay":  c.Overlay2.String(),
   450  		"fsmode":   fsMode,
   451  		"cpuarch":  runtime.GOARCH,
   452  		"go":       runtime.Version(),
   453  		// The "experiment" label is currently unused, but may be used to contain
   454  		// extra information about e.g. an experiment that may be enabled.
   455  		"experiment": "",
   456  	}
   457  }
   458  
   459  // FileAccessType tells how the filesystem is accessed.
   460  type FileAccessType int
   461  
   462  const (
   463  	// FileAccessExclusive gives the sandbox exclusive access over files and
   464  	// directories in the filesystem. No external modifications are permitted and
   465  	// can lead to undefined behavior.
   466  	//
   467  	// Exclusive filesystem access enables more aggressive caching and offers
   468  	// significantly better performance. This is the default mode for the root
   469  	// volume.
   470  	FileAccessExclusive FileAccessType = iota
   471  
   472  	// FileAccessShared is used for volumes that can have external changes. It
   473  	// requires revalidation on every filesystem access to detect external
   474  	// changes, and reduces the amount of caching that can be done. This is the
   475  	// default mode for non-root volumes.
   476  	FileAccessShared
   477  )
   478  
   479  func fileAccessTypePtr(v FileAccessType) *FileAccessType {
   480  	return &v
   481  }
   482  
   483  // Set implements flag.Value. Set(String()) should be idempotent.
   484  func (f *FileAccessType) Set(v string) error {
   485  	switch v {
   486  	case "shared":
   487  		*f = FileAccessShared
   488  	case "exclusive":
   489  		*f = FileAccessExclusive
   490  	default:
   491  		return fmt.Errorf("invalid file access type %q", v)
   492  	}
   493  	return nil
   494  }
   495  
   496  // Get implements flag.Value.
   497  func (f *FileAccessType) Get() any {
   498  	return *f
   499  }
   500  
   501  // String implements flag.Value.
   502  func (f FileAccessType) String() string {
   503  	switch f {
   504  	case FileAccessShared:
   505  		return "shared"
   506  	case FileAccessExclusive:
   507  		return "exclusive"
   508  	}
   509  	panic(fmt.Sprintf("Invalid file access type %d", f))
   510  }
   511  
   512  // NetworkType tells which network stack to use.
   513  type NetworkType int
   514  
   515  const (
   516  	// NetworkSandbox uses internal network stack, isolated from the host.
   517  	NetworkSandbox NetworkType = iota
   518  
   519  	// NetworkHost redirects network related syscalls to the host network.
   520  	NetworkHost
   521  
   522  	// NetworkNone sets up just loopback using netstack.
   523  	NetworkNone
   524  )
   525  
   526  func networkTypePtr(v NetworkType) *NetworkType {
   527  	return &v
   528  }
   529  
   530  // Set implements flag.Value. Set(String()) should be idempotent.
   531  func (n *NetworkType) Set(v string) error {
   532  	switch v {
   533  	case "sandbox":
   534  		*n = NetworkSandbox
   535  	case "host":
   536  		*n = NetworkHost
   537  	case "none":
   538  		*n = NetworkNone
   539  	default:
   540  		return fmt.Errorf("invalid network type %q", v)
   541  	}
   542  	return nil
   543  }
   544  
   545  // Get implements flag.Value.
   546  func (n *NetworkType) Get() any {
   547  	return *n
   548  }
   549  
   550  // String implements flag.Value.
   551  func (n NetworkType) String() string {
   552  	switch n {
   553  	case NetworkSandbox:
   554  		return "sandbox"
   555  	case NetworkHost:
   556  		return "host"
   557  	case NetworkNone:
   558  		return "none"
   559  	}
   560  	panic(fmt.Sprintf("Invalid network type %d", n))
   561  }
   562  
   563  // QueueingDiscipline is used to specify the kind of Queueing Discipline to
   564  // apply for a give FDBasedLink.
   565  type QueueingDiscipline int
   566  
   567  const (
   568  	// QDiscNone disables any queueing for the underlying FD.
   569  	QDiscNone QueueingDiscipline = iota
   570  
   571  	// QDiscFIFO applies a simple fifo based queue to the underlying FD.
   572  	QDiscFIFO
   573  )
   574  
   575  func queueingDisciplinePtr(v QueueingDiscipline) *QueueingDiscipline {
   576  	return &v
   577  }
   578  
   579  // Set implements flag.Value. Set(String()) should be idempotent.
   580  func (q *QueueingDiscipline) Set(v string) error {
   581  	switch v {
   582  	case "none":
   583  		*q = QDiscNone
   584  	case "fifo":
   585  		*q = QDiscFIFO
   586  	default:
   587  		return fmt.Errorf("invalid qdisc %q", v)
   588  	}
   589  	return nil
   590  }
   591  
   592  // Get implements flag.Value.
   593  func (q *QueueingDiscipline) Get() any {
   594  	return *q
   595  }
   596  
   597  // String implements flag.Value.
   598  func (q QueueingDiscipline) String() string {
   599  	switch q {
   600  	case QDiscNone:
   601  		return "none"
   602  	case QDiscFIFO:
   603  		return "fifo"
   604  	}
   605  	panic(fmt.Sprintf("Invalid qdisc %d", q))
   606  }
   607  
   608  func leakModePtr(v refs.LeakMode) *refs.LeakMode {
   609  	return &v
   610  }
   611  
   612  func watchdogActionPtr(v watchdog.Action) *watchdog.Action {
   613  	return &v
   614  }
   615  
   616  // HostUDS tells how much of the host UDS the file system has access to.
   617  type HostUDS int
   618  
   619  const (
   620  	// HostUDSNone doesn't allows UDS from the host to be manipulated.
   621  	HostUDSNone HostUDS = 0x0
   622  
   623  	// HostUDSOpen allows UDS from the host to be opened, e.g. connect(2).
   624  	HostUDSOpen HostUDS = 0x1
   625  
   626  	// HostUDSCreate allows UDS from the host to be created, e.g. bind(2).
   627  	HostUDSCreate HostUDS = 0x2
   628  
   629  	// HostUDSAll allows all form of communication with the host through UDS.
   630  	HostUDSAll = HostUDSOpen | HostUDSCreate
   631  )
   632  
   633  func hostUDSPtr(v HostUDS) *HostUDS {
   634  	return &v
   635  }
   636  
   637  // Set implements flag.Value. Set(String()) should be idempotent.
   638  func (g *HostUDS) Set(v string) error {
   639  	switch v {
   640  	case "", "none":
   641  		*g = HostUDSNone
   642  	case "open":
   643  		*g = HostUDSOpen
   644  	case "create":
   645  		*g = HostUDSCreate
   646  	case "all":
   647  		*g = HostUDSAll
   648  	default:
   649  		return fmt.Errorf("invalid host UDS type %q", v)
   650  	}
   651  	return nil
   652  }
   653  
   654  // Get implements flag.Value.
   655  func (g *HostUDS) Get() any {
   656  	return *g
   657  }
   658  
   659  // String implements flag.Value.
   660  func (g HostUDS) String() string {
   661  	switch g {
   662  	case HostUDSNone:
   663  		return "none"
   664  	case HostUDSOpen:
   665  		return "open"
   666  	case HostUDSCreate:
   667  		return "create"
   668  	case HostUDSAll:
   669  		return "all"
   670  	default:
   671  		panic(fmt.Sprintf("Invalid host UDS type %d", g))
   672  	}
   673  }
   674  
   675  // AllowOpen returns true if it can consume UDS from the host.
   676  func (g HostUDS) AllowOpen() bool {
   677  	return g&HostUDSOpen != 0
   678  }
   679  
   680  // AllowCreate returns true if it can create UDS in the host.
   681  func (g HostUDS) AllowCreate() bool {
   682  	return g&HostUDSCreate != 0
   683  }
   684  
   685  // HostFifo tells how much of the host FIFO (or named pipes) the file system has
   686  // access to.
   687  type HostFifo int
   688  
   689  const (
   690  	// HostFifoNone doesn't allow FIFO from the host to be manipulated.
   691  	HostFifoNone HostFifo = 0x0
   692  
   693  	// HostFifoOpen allows FIFOs from the host to be opened.
   694  	HostFifoOpen HostFifo = 0x1
   695  )
   696  
   697  func hostFifoPtr(v HostFifo) *HostFifo {
   698  	return &v
   699  }
   700  
   701  // Set implements flag.Value. Set(String()) should be idempotent.
   702  func (g *HostFifo) Set(v string) error {
   703  	switch v {
   704  	case "", "none":
   705  		*g = HostFifoNone
   706  	case "open":
   707  		*g = HostFifoOpen
   708  	default:
   709  		return fmt.Errorf("invalid host fifo type %q", v)
   710  	}
   711  	return nil
   712  }
   713  
   714  // Get implements flag.Value.
   715  func (g *HostFifo) Get() any {
   716  	return *g
   717  }
   718  
   719  // String implements flag.Value.
   720  func (g HostFifo) String() string {
   721  	switch g {
   722  	case HostFifoNone:
   723  		return "none"
   724  	case HostFifoOpen:
   725  		return "open"
   726  	default:
   727  		panic(fmt.Sprintf("Invalid host fifo type %d", g))
   728  	}
   729  }
   730  
   731  // AllowOpen returns true if it can consume FIFOs from the host.
   732  func (g HostFifo) AllowOpen() bool {
   733  	return g&HostFifoOpen != 0
   734  }
   735  
   736  // Overlay2 holds the configuration for setting up overlay filesystems for the
   737  // container.
   738  type Overlay2 struct {
   739  	rootMount bool
   740  	subMounts bool
   741  	medium    string
   742  }
   743  
   744  func defaultOverlay2() *Overlay2 {
   745  	// Rootfs overlay is enabled by default and backed by a file in rootfs itself.
   746  	return &Overlay2{rootMount: true, subMounts: false, medium: "self"}
   747  }
   748  
   749  // Set implements flag.Value. Set(String()) should be idempotent.
   750  func (o *Overlay2) Set(v string) error {
   751  	if v == "none" {
   752  		o.rootMount = false
   753  		o.subMounts = false
   754  		o.medium = ""
   755  		return nil
   756  	}
   757  	vs := strings.Split(v, ":")
   758  	if len(vs) != 2 {
   759  		return fmt.Errorf("expected format is --overlay2={mount}:{medium}, got %q", v)
   760  	}
   761  
   762  	switch mount := vs[0]; mount {
   763  	case "root":
   764  		o.rootMount = true
   765  	case "all":
   766  		o.rootMount = true
   767  		o.subMounts = true
   768  	default:
   769  		return fmt.Errorf("unexpected mount specifier for --overlay2: %q", mount)
   770  	}
   771  
   772  	o.medium = vs[1]
   773  	switch o.medium {
   774  	case "memory", "self": // OK
   775  	default:
   776  		if !strings.HasPrefix(o.medium, "dir=") {
   777  			return fmt.Errorf("unexpected medium specifier for --overlay2: %q", o.medium)
   778  		}
   779  		if hostFileDir := strings.TrimPrefix(o.medium, "dir="); !filepath.IsAbs(hostFileDir) {
   780  			return fmt.Errorf("overlay host file directory should be an absolute path, got %q", hostFileDir)
   781  		}
   782  	}
   783  	return nil
   784  }
   785  
   786  // Get implements flag.Value.
   787  func (o *Overlay2) Get() any {
   788  	return *o
   789  }
   790  
   791  // String implements flag.Value.
   792  func (o Overlay2) String() string {
   793  	if !o.rootMount && !o.subMounts {
   794  		return "none"
   795  	}
   796  	res := ""
   797  	switch {
   798  	case o.rootMount && o.subMounts:
   799  		res = "all"
   800  	case o.rootMount:
   801  		res = "root"
   802  	default:
   803  		panic("invalid state of subMounts = true and rootMount = false")
   804  	}
   805  
   806  	return res + ":" + o.medium
   807  }
   808  
   809  // Enabled returns true if the overlay option is enabled for any mounts.
   810  func (o *Overlay2) Enabled() bool {
   811  	return o.rootMount || o.subMounts
   812  }
   813  
   814  // RootEnabled returns true if the overlay is enabled for the root mount.
   815  func (o *Overlay2) RootEnabled() bool {
   816  	return o.rootMount
   817  }
   818  
   819  // SubMountEnabled returns true if the overlay is enabled for submounts.
   820  func (o *Overlay2) SubMountEnabled() bool {
   821  	return o.subMounts
   822  }
   823  
   824  // IsBackedByMemory indicates whether the overlay is backed by app memory.
   825  func (o *Overlay2) IsBackedByMemory() bool {
   826  	return o.Enabled() && o.medium == "memory"
   827  }
   828  
   829  // IsBackedBySelf indicates whether the overlaid mounts are backed by
   830  // themselves.
   831  func (o *Overlay2) IsBackedBySelf() bool {
   832  	return o.Enabled() && o.medium == "self"
   833  }
   834  
   835  // HostFileDir indicates the directory in which the overlay-backing host file
   836  // should be created.
   837  //
   838  // Precondition: o.IsBackedByHostFile() && !o.IsBackedBySelf().
   839  func (o *Overlay2) HostFileDir() string {
   840  	if !strings.HasPrefix(o.medium, "dir=") {
   841  		panic(fmt.Sprintf("Overlay2.Medium = %q does not have dir= prefix when overlay is backed by a host file", o.medium))
   842  	}
   843  	hostFileDir := strings.TrimPrefix(o.medium, "dir=")
   844  	if !filepath.IsAbs(hostFileDir) {
   845  		panic(fmt.Sprintf("overlay host file directory should be an absolute path, got %q", hostFileDir))
   846  	}
   847  	return hostFileDir
   848  }