mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-29 04:04:45 +00:00
gpu: Add config to TOML
Update cold-plug and hot-plug setting to include bridge, root and switch-port Signed-off-by: Zvonko Kaiser <zkaiser@nvidia.com>
This commit is contained in:
parent
da42801c38
commit
55a66eb7fb
@ -352,8 +352,15 @@ pflashes = []
|
||||
# Default false
|
||||
#hotplug_vfio_on_root_bus = true
|
||||
|
||||
# Enable hot-plugging of VFIO devices to a bridge-port,
|
||||
# root-port or switch-port.
|
||||
# The default setting is "no-port"
|
||||
#hot_plug_vfio = "root-port"
|
||||
|
||||
# In a confidential compute environment hot-plugging can compromise
|
||||
# security. Enable cold-plugging of VFIO devices to a root-port.
|
||||
# security.
|
||||
# Enable cold-plugging of VFIO devices to a bridge-port,
|
||||
# root-port or switch-port.
|
||||
# The default setting is "no-port", which means disabled.
|
||||
#cold_plug_vfio = "root-port"
|
||||
|
||||
|
@ -47,7 +47,7 @@ func deviceLogger() *logrus.Entry {
|
||||
return api.DeviceLogger()
|
||||
}
|
||||
|
||||
// IsPCIeDevice Identify PCIe device by reading the size of the PCI config space
|
||||
// IsPCIeDevice Identifies PCIe device by reading the size of the PCI config space
|
||||
// Plain PCI device have 256 bytes of config space where PCIe devices have 4K
|
||||
func IsPCIeDevice(bdf string) bool {
|
||||
if len(strings.Split(bdf, ":")) == 2 {
|
||||
@ -157,9 +157,7 @@ func checkIgnorePCIClass(pciClass string, deviceBDF string, bitmask uint64) (boo
|
||||
|
||||
// GetAllVFIODevicesFromIOMMUGroup returns all the VFIO devices in the IOMMU group
|
||||
// We can reuse this function at various levels, sandbox, container.
|
||||
// Only the VFIO module is allowed to do bus assignments, all other modules need to
|
||||
// ignore it if used as helper function to get VFIO information.
|
||||
func GetAllVFIODevicesFromIOMMUGroup(device config.DeviceInfo, ignoreBusAssignment bool) ([]*config.VFIODev, error) {
|
||||
func GetAllVFIODevicesFromIOMMUGroup(device config.DeviceInfo) ([]*config.VFIODev, error) {
|
||||
|
||||
vfioDevs := []*config.VFIODev{}
|
||||
|
||||
@ -207,8 +205,8 @@ func GetAllVFIODevicesFromIOMMUGroup(device config.DeviceInfo, ignoreBusAssignme
|
||||
Class: pciClass,
|
||||
Rank: -1,
|
||||
}
|
||||
if isPCIe && !ignoreBusAssignment {
|
||||
vfioPCI.Bus = fmt.Sprintf("%s%d", pcieRootPortPrefix, len(AllPCIeDevs))
|
||||
if isPCIe {
|
||||
vfioPCI.Rank = len(AllPCIeDevs)
|
||||
AllPCIeDevs[deviceBDF] = true
|
||||
}
|
||||
vfio = vfioPCI
|
||||
|
@ -73,7 +73,7 @@ func (device *VFIODevice) Attach(ctx context.Context, devReceiver api.DeviceRece
|
||||
}
|
||||
}()
|
||||
|
||||
device.VfioDevs, err = GetAllVFIODevicesFromIOMMUGroup(*device.DeviceInfo, false)
|
||||
device.VfioDevs, err = GetAllVFIODevicesFromIOMMUGroup(*device.DeviceInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ const defaultVMCacheEndpoint string = "/var/run/kata-containers/cache.sock"
|
||||
// Default config file used by stateless systems.
|
||||
var defaultRuntimeConfiguration = "@CONFIG_PATH@"
|
||||
|
||||
const defaultHotPlugVFIO = hv.BridgePort
|
||||
const defaultHotPlugVFIO = hv.NoPort
|
||||
const defaultColdPlugVFIO = hv.NoPort
|
||||
|
||||
|
||||
|
@ -76,6 +76,7 @@ type factory struct {
|
||||
VMCacheNumber uint `toml:"vm_cache_number"`
|
||||
Template bool `toml:"enable_template"`
|
||||
}
|
||||
|
||||
type hypervisor struct {
|
||||
Path string `toml:"path"`
|
||||
JailerPath string `toml:"jailer_path"`
|
||||
@ -886,6 +887,7 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
|
||||
GuestMemoryDumpPath: h.GuestMemoryDumpPath,
|
||||
GuestMemoryDumpPaging: h.GuestMemoryDumpPaging,
|
||||
ConfidentialGuest: h.ConfidentialGuest,
|
||||
SevSnpGuest: h.SevSnpGuest,
|
||||
GuestSwap: h.GuestSwap,
|
||||
Rootless: h.Rootless,
|
||||
LegacySerial: h.LegacySerial,
|
||||
@ -1677,10 +1679,7 @@ func checkConfig(config oci.RuntimeConfig) error {
|
||||
hotPlugVFIO := config.HypervisorConfig.HotPlugVFIO
|
||||
coldPlugVFIO := config.HypervisorConfig.ColdPlugVFIO
|
||||
machineType := config.HypervisorConfig.HypervisorMachineType
|
||||
if err := checkPCIeConfig(coldPlugVFIO, machineType); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkPCIeConfig(hotPlugVFIO, machineType); err != nil {
|
||||
if err := checkPCIeConfig(coldPlugVFIO, hotPlugVFIO, machineType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -1690,19 +1689,29 @@ func checkConfig(config oci.RuntimeConfig) error {
|
||||
// checkPCIeConfig ensures the PCIe configuration is valid.
|
||||
// Only allow one of the following settings for cold-plug:
|
||||
// no-port, root-port, switch-port
|
||||
func checkPCIeConfig(vfioPort hv.PCIePort, machineType string) error {
|
||||
func checkPCIeConfig(coldPlug hv.PCIePort, hotPlug hv.PCIePort, machineType string) error {
|
||||
// Currently only QEMU q35 supports advanced PCIe topologies
|
||||
// firecracker, dragonball do not have right now any PCIe support
|
||||
if machineType != "q35" {
|
||||
return nil
|
||||
}
|
||||
if vfioPort == hv.NoPort || vfioPort == hv.BridgePort ||
|
||||
vfioPort == hv.RootPort || vfioPort == hv.SwitchPort {
|
||||
|
||||
if coldPlug != hv.NoPort && hotPlug != hv.NoPort {
|
||||
return fmt.Errorf("invalid hot-plug=%s and cold-plug=%s settings, only one of them can be set", coldPlug, hotPlug)
|
||||
}
|
||||
var port hv.PCIePort
|
||||
if coldPlug != hv.NoPort {
|
||||
port = coldPlug
|
||||
}
|
||||
if hotPlug != hv.NoPort {
|
||||
port = hotPlug
|
||||
}
|
||||
if port == hv.NoPort || port == hv.BridgePort || port == hv.RootPort || port == hv.SwitchPort {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("invalid vfio_port=%s setting, allowed values %s, %s, %s, %s",
|
||||
vfioPort, hv.NoPort, hv.BridgePort, hv.RootPort, hv.SwitchPort)
|
||||
coldPlug, hv.NoPort, hv.BridgePort, hv.RootPort, hv.SwitchPort)
|
||||
}
|
||||
|
||||
// checkNetNsConfig performs sanity checks on disable_new_netns config.
|
||||
|
@ -821,22 +821,22 @@ func TestRegexpContains(t *testing.T) {
|
||||
|
||||
//nolint: govet
|
||||
type testData struct {
|
||||
toMatch string
|
||||
regexps []string
|
||||
toMatch string
|
||||
expected bool
|
||||
}
|
||||
|
||||
data := []testData{
|
||||
{regexps: []string{}, toMatch: "", expected: false},
|
||||
{regexps: []string{}, toMatch: "nonempty", expected: false},
|
||||
{regexps: []string{"simple"}, toMatch: "simple", expected: true},
|
||||
{regexps: []string{"simple"}, toMatch: "some_simple_text", expected: true},
|
||||
{regexps: []string{"simple"}, toMatch: "simp", expected: false},
|
||||
{regexps: []string{"one", "two"}, toMatch: "one", expected: true},
|
||||
{regexps: []string{"one", "two"}, toMatch: "two", expected: true},
|
||||
{regexps: []string{"o*"}, toMatch: "oooo", expected: true},
|
||||
{regexps: []string{"o*"}, toMatch: "oooa", expected: true},
|
||||
{regexps: []string{"^o*$"}, toMatch: "oooa", expected: false},
|
||||
{[]string{}, "", false},
|
||||
{[]string{}, "nonempty", false},
|
||||
{[]string{"simple"}, "simple", true},
|
||||
{[]string{"simple"}, "some_simple_text", true},
|
||||
{[]string{"simple"}, "simp", false},
|
||||
{[]string{"one", "two"}, "one", true},
|
||||
{[]string{"one", "two"}, "two", true},
|
||||
{[]string{"o*"}, "oooo", true},
|
||||
{[]string{"o*"}, "oooa", true},
|
||||
{[]string{"^o*$"}, "oooa", false},
|
||||
}
|
||||
|
||||
for _, d := range data {
|
||||
@ -850,25 +850,25 @@ func TestCheckPathIsInGlobs(t *testing.T) {
|
||||
|
||||
//nolint: govet
|
||||
type testData struct {
|
||||
toMatch string
|
||||
globs []string
|
||||
toMatch string
|
||||
expected bool
|
||||
}
|
||||
|
||||
data := []testData{
|
||||
{globs: []string{}, toMatch: "", expected: false},
|
||||
{globs: []string{}, toMatch: "nonempty", expected: false},
|
||||
{globs: []string{"simple"}, toMatch: "simple", expected: false},
|
||||
{globs: []string{"simple"}, toMatch: "some_simple_text", expected: false},
|
||||
{globs: []string{"/bin/ls"}, toMatch: "/bin/ls", expected: true},
|
||||
{globs: []string{"/bin/ls", "/bin/false"}, toMatch: "/bin/ls", expected: true},
|
||||
{globs: []string{"/bin/ls", "/bin/false"}, toMatch: "/bin/false", expected: true},
|
||||
{globs: []string{"/bin/ls", "/bin/false"}, toMatch: "/bin/bar", expected: false},
|
||||
{globs: []string{"/bin/*ls*"}, toMatch: "/bin/ls", expected: true},
|
||||
{globs: []string{"/bin/*ls*"}, toMatch: "/bin/false", expected: true},
|
||||
{globs: []string{"bin/ls"}, toMatch: "/bin/ls", expected: false},
|
||||
{globs: []string{"./bin/ls"}, toMatch: "/bin/ls", expected: false},
|
||||
{globs: []string{"*/bin/ls"}, toMatch: "/bin/ls", expected: false},
|
||||
{[]string{}, "", false},
|
||||
{[]string{}, "nonempty", false},
|
||||
{[]string{"simple"}, "simple", false},
|
||||
{[]string{"simple"}, "some_simple_text", false},
|
||||
{[]string{"/bin/ls"}, "/bin/ls", true},
|
||||
{[]string{"/bin/ls", "/bin/false"}, "/bin/ls", true},
|
||||
{[]string{"/bin/ls", "/bin/false"}, "/bin/false", true},
|
||||
{[]string{"/bin/ls", "/bin/false"}, "/bin/bar", false},
|
||||
{[]string{"/bin/*ls*"}, "/bin/ls", true},
|
||||
{[]string{"/bin/*ls*"}, "/bin/false", true},
|
||||
{[]string{"bin/ls"}, "/bin/ls", false},
|
||||
{[]string{"./bin/ls"}, "/bin/ls", false},
|
||||
{[]string{"*/bin/ls"}, "/bin/ls", false},
|
||||
}
|
||||
|
||||
for _, d := range data {
|
||||
@ -923,10 +923,10 @@ func TestParseAnnotationUintConfiguration(t *testing.T) {
|
||||
|
||||
// nolint: govet
|
||||
testCases := []struct {
|
||||
err error
|
||||
annotations map[string]string
|
||||
validFunc func(uint64) error
|
||||
expected uint64
|
||||
err error
|
||||
validFunc func(uint64) error
|
||||
}{
|
||||
{
|
||||
annotations: map[string]string{key: ""},
|
||||
@ -1007,10 +1007,10 @@ func TestParseAnnotationBoolConfiguration(t *testing.T) {
|
||||
|
||||
// nolint: govet
|
||||
testCases := []struct {
|
||||
err error
|
||||
annotationKey string
|
||||
annotationValueList []string
|
||||
expected bool
|
||||
err error
|
||||
}{
|
||||
{
|
||||
annotationKey: boolKey,
|
||||
@ -1207,8 +1207,8 @@ func TestNewMount(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
testCases := []struct {
|
||||
in specs.Mount
|
||||
out vc.Mount
|
||||
in specs.Mount
|
||||
}{
|
||||
{
|
||||
in: specs.Mount{
|
||||
|
@ -45,10 +45,10 @@ type AcrnState struct {
|
||||
|
||||
// Acrn is an Hypervisor interface implementation for the Linux acrn hypervisor.
|
||||
type Acrn struct {
|
||||
sandbox *Sandbox
|
||||
ctx context.Context
|
||||
arch acrnArch
|
||||
store persistapi.PersistDriver
|
||||
sandbox *Sandbox
|
||||
id string
|
||||
acrnConfig Config
|
||||
config HypervisorConfig
|
||||
|
@ -246,15 +246,15 @@ func (s *CloudHypervisorState) reset() {
|
||||
}
|
||||
|
||||
type cloudHypervisor struct {
|
||||
vmconfig chclient.VmConfig
|
||||
console console.Console
|
||||
virtiofsDaemon VirtiofsDaemon
|
||||
ctx context.Context
|
||||
APIClient clhClient
|
||||
ctx context.Context
|
||||
id string
|
||||
netDevices *[]chclient.NetConfig
|
||||
devicesIds map[string]string
|
||||
netDevicesFiles map[string][]*os.File
|
||||
id string
|
||||
vmconfig chclient.VmConfig
|
||||
state CloudHypervisorState
|
||||
config HypervisorConfig
|
||||
stopped int32
|
||||
|
@ -188,13 +188,13 @@ func TestCloudHypervisorAddNetCheckEnpointTypes(t *testing.T) {
|
||||
}
|
||||
// nolint: govet
|
||||
tests := []struct {
|
||||
args args
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{name: "TapEndpoint", args: args{e: &TapEndpoint{}}, wantErr: true},
|
||||
{name: "Empty VethEndpoint", args: args{e: &VethEndpoint{}}, wantErr: true},
|
||||
{name: "Valid VethEndpoint", args: args{e: validVeth}, wantErr: false},
|
||||
{"TapEndpoint", args{e: &TapEndpoint{}}, true},
|
||||
{"Empty VethEndpoint", args{e: &VethEndpoint{}}, true},
|
||||
{"Valid VethEndpoint", args{e: validVeth}, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -507,7 +507,7 @@ type HypervisorConfig struct {
|
||||
|
||||
// RawDevics are used to get PCIe device info early before the sandbox
|
||||
// is started to make better PCIe topology decisions
|
||||
RawDevices []config.DeviceInfo
|
||||
VFIODevices []config.DeviceInfo
|
||||
|
||||
// HotplugVFIO is used to indicate if devices need to be hotplugged on the
|
||||
// root port or a switch
|
||||
|
@ -284,16 +284,23 @@ type KataAgentState struct {
|
||||
|
||||
// nolint: govet
|
||||
type kataAgent struct {
|
||||
ctx context.Context
|
||||
vmSocket interface{}
|
||||
client *kataclient.AgentClient
|
||||
reqHandlers map[string]reqFunc
|
||||
state KataAgentState
|
||||
kmodules []string
|
||||
ctx context.Context
|
||||
vmSocket interface{}
|
||||
|
||||
client *kataclient.AgentClient
|
||||
|
||||
// lock protects the client pointer
|
||||
sync.Mutex
|
||||
|
||||
state KataAgentState
|
||||
|
||||
reqHandlers map[string]reqFunc
|
||||
kmodules []string
|
||||
|
||||
dialTimout uint32
|
||||
keepConn bool
|
||||
dead bool
|
||||
|
||||
keepConn bool
|
||||
dead bool
|
||||
}
|
||||
|
||||
func (k *kataAgent) Logger() *logrus.Entry {
|
||||
|
@ -235,10 +235,10 @@ func TestHandleDeviceBlockVolume(t *testing.T) {
|
||||
|
||||
// nolint: govet
|
||||
tests := []struct {
|
||||
inputDev *drivers.BlockDevice
|
||||
resultVol *pb.Storage
|
||||
BlockDeviceDriver string
|
||||
inputMount Mount
|
||||
inputDev *drivers.BlockDevice
|
||||
resultVol *pb.Storage
|
||||
}{
|
||||
{
|
||||
inputDev: &drivers.BlockDevice{
|
||||
@ -1024,10 +1024,10 @@ func TestKataAgentKernelParams(t *testing.T) {
|
||||
|
||||
// nolint: govet
|
||||
type testData struct {
|
||||
expectedParams []Param
|
||||
containerPipeSize uint32
|
||||
debug bool
|
||||
trace bool
|
||||
containerPipeSize uint32
|
||||
expectedParams []Param
|
||||
}
|
||||
|
||||
debugParam := Param{Key: "agent.log", Value: "debug"}
|
||||
@ -1036,28 +1036,28 @@ func TestKataAgentKernelParams(t *testing.T) {
|
||||
containerPipeSizeParam := Param{Key: vcAnnotations.ContainerPipeSizeKernelParam, Value: "2097152"}
|
||||
|
||||
data := []testData{
|
||||
{debug: false, trace: false, containerPipeSize: 0, expectedParams: []Param{}},
|
||||
{false, false, 0, []Param{}},
|
||||
|
||||
// Debug
|
||||
{debug: true, trace: false, containerPipeSize: 0, expectedParams: []Param{debugParam}},
|
||||
{true, false, 0, []Param{debugParam}},
|
||||
|
||||
// Tracing
|
||||
{debug: false, trace: true, containerPipeSize: 0, expectedParams: []Param{traceParam}},
|
||||
{false, true, 0, []Param{traceParam}},
|
||||
|
||||
// Debug + Tracing
|
||||
{debug: true, trace: true, containerPipeSize: 0, expectedParams: []Param{debugParam, traceParam}},
|
||||
{true, true, 0, []Param{debugParam, traceParam}},
|
||||
|
||||
// pipesize
|
||||
{debug: false, trace: false, containerPipeSize: 2097152, expectedParams: []Param{containerPipeSizeParam}},
|
||||
{false, false, 0, []Param{containerPipeSizeParam}},
|
||||
|
||||
// Debug + pipesize
|
||||
{debug: true, trace: false, containerPipeSize: 2097152, expectedParams: []Param{debugParam, containerPipeSizeParam}},
|
||||
{true, false, 0, []Param{debugParam, containerPipeSizeParam}},
|
||||
|
||||
// Tracing + pipesize
|
||||
{debug: false, trace: true, containerPipeSize: 2097152, expectedParams: []Param{traceParam, containerPipeSizeParam}},
|
||||
{false, true, 0, []Param{traceParam, containerPipeSizeParam}},
|
||||
|
||||
// Debug + Tracing + pipesize
|
||||
{debug: true, trace: true, containerPipeSize: 2097152, expectedParams: []Param{debugParam, traceParam, containerPipeSizeParam}},
|
||||
{true, true, 0, []Param{debugParam, traceParam, containerPipeSizeParam}},
|
||||
}
|
||||
|
||||
for i, d := range data {
|
||||
|
@ -22,12 +22,15 @@ var monitorLog = virtLog.WithField("subsystem", "virtcontainers/monitor")
|
||||
|
||||
// nolint: govet
|
||||
type monitor struct {
|
||||
sandbox *Sandbox
|
||||
stopCh chan bool
|
||||
watchers []chan error
|
||||
checkInterval time.Duration
|
||||
wg sync.WaitGroup
|
||||
watchers []chan error
|
||||
sandbox *Sandbox
|
||||
|
||||
wg sync.WaitGroup
|
||||
sync.Mutex
|
||||
|
||||
stopCh chan bool
|
||||
checkInterval time.Duration
|
||||
|
||||
running bool
|
||||
}
|
||||
|
||||
|
@ -747,9 +747,8 @@ func (q *qemu) checkBpfEnabled() {
|
||||
// There is only 64kB of IO memory each root,switch port will consume 4k hence
|
||||
// only 16 ports possible.
|
||||
func (q *qemu) createPCIeTopology(qemuConfig *govmmQemu.Config, hypervisorConfig *HypervisorConfig) error {
|
||||
// We do not need to do anything if we want to hotplug a VFIO to a
|
||||
// pcie-pci-bridge, just return
|
||||
if hypervisorConfig.HotPlugVFIO == hv.BridgePort {
|
||||
// If no-port set just return no need to add PCIe Root Port or PCIe Switches
|
||||
if hypervisorConfig.HotPlugVFIO == hv.NoPort && hypervisorConfig.ColdPlugVFIO == hv.NoPort {
|
||||
return nil
|
||||
}
|
||||
// Add PCIe Root Port or PCIe Switches to the hypervisor
|
||||
@ -772,37 +771,27 @@ func (q *qemu) createPCIeTopology(qemuConfig *govmmQemu.Config, hypervisorConfig
|
||||
qemuConfig.FwCfg = append(qemuConfig.FwCfg, fwCfg)
|
||||
}
|
||||
|
||||
// Get the number of hotpluggable ports needed from the provided devices
|
||||
var numOfHotPluggablePorts uint32 = 0
|
||||
for _, dev := range hypervisorConfig.RawDevices {
|
||||
hostPath, _ := config.GetHostPath(dev, false, "")
|
||||
if hostPath == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
vfioNumberOrContainer := filepath.Base(hostPath)
|
||||
// If we want to have VFIO inside of the VM we need to passthrough
|
||||
// additionally /dev/vfio/vfio which is the VFIO "container".
|
||||
// Ignore it and handle the remaining devices.
|
||||
if strings.Compare(vfioNumberOrContainer, "vfio") == 0 {
|
||||
continue
|
||||
}
|
||||
iommuDevicesPath := filepath.Join(config.SysIOMMUGroupPath, vfioNumberOrContainer, "devices")
|
||||
deviceFiles, err := os.ReadDir(iommuDevicesPath)
|
||||
// Get the number of hot(cold)-pluggable ports needed from the provided devices
|
||||
var numOfPluggablePorts uint32 = 0
|
||||
for _, dev := range hypervisorConfig.VFIODevices {
|
||||
var err error
|
||||
dev.HostPath, err = config.GetHostPath(dev, false, "")
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Cannot get host path for device: %v err: %v", dev, err)
|
||||
}
|
||||
|
||||
for _, deviceFile := range deviceFiles {
|
||||
deviceBDF, _, _, err := drivers.GetVFIODetails(deviceFile.Name(), iommuDevicesPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if drivers.IsPCIeDevice(deviceBDF) {
|
||||
numOfHotPluggablePorts = numOfHotPluggablePorts + 1
|
||||
devicesPerIOMMUGroup, err := drivers.GetAllVFIODevicesFromIOMMUGroup(dev)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot get all VFIO devices from IOMMU group with device: %v err: %v", dev, err)
|
||||
}
|
||||
for _, vfioDevice := range devicesPerIOMMUGroup {
|
||||
if drivers.IsPCIeDevice(vfioDevice.BDF) {
|
||||
numOfPluggablePorts = numOfPluggablePorts + 1
|
||||
}
|
||||
// Reset the Rank, the vfio module is going to assign the correct one
|
||||
vfioDevice.Rank = -1
|
||||
}
|
||||
}
|
||||
drivers.AllPCIeDevs = make(map[string]bool)
|
||||
|
||||
// If number of PCIe root ports > 16 then bail out otherwise we may
|
||||
// use up all slots or IO memory on the root bus and vfio-XXX-pci devices
|
||||
@ -817,20 +806,20 @@ func (q *qemu) createPCIeTopology(qemuConfig *govmmQemu.Config, hypervisorConfig
|
||||
|
||||
// If the user provided more root ports than we have detected
|
||||
// use the user provided number of PCIe root ports
|
||||
if numOfHotPluggablePorts < hypervisorConfig.PCIeRootPort {
|
||||
numOfHotPluggablePorts = hypervisorConfig.PCIeRootPort
|
||||
if numOfPluggablePorts < hypervisorConfig.PCIeRootPort {
|
||||
numOfPluggablePorts = hypervisorConfig.PCIeRootPort
|
||||
}
|
||||
// If the user provided more switch ports than we have detected
|
||||
// use the user provided number of PCIe root ports
|
||||
if numOfHotPluggablePorts < hypervisorConfig.PCIeSwitchPort {
|
||||
numOfHotPluggablePorts = hypervisorConfig.PCIeSwitchPort
|
||||
if numOfPluggablePorts < hypervisorConfig.PCIeSwitchPort {
|
||||
numOfPluggablePorts = hypervisorConfig.PCIeSwitchPort
|
||||
}
|
||||
|
||||
if q.state.HotPlugVFIO == hv.RootPort || q.state.HotplugVFIOOnRootBus {
|
||||
qemuConfig.Devices = q.arch.appendPCIeRootPortDevice(qemuConfig.Devices, numOfHotPluggablePorts, memSize32bit, memSize64bit)
|
||||
if q.state.HotPlugVFIO == hv.RootPort || q.state.ColdPlugVFIO == hv.RootPort || q.state.HotplugVFIOOnRootBus {
|
||||
qemuConfig.Devices = q.arch.appendPCIeRootPortDevice(qemuConfig.Devices, numOfPluggablePorts, memSize32bit, memSize64bit)
|
||||
}
|
||||
if q.state.HotPlugVFIO == hv.SwitchPort {
|
||||
qemuConfig.Devices = q.arch.appendPCIeSwitchPortDevice(qemuConfig.Devices, numOfHotPluggablePorts, memSize32bit, memSize64bit)
|
||||
if q.state.HotPlugVFIO == hv.SwitchPort || q.state.ColdPlugVFIO == hv.SwitchPort {
|
||||
qemuConfig.Devices = q.arch.appendPCIeSwitchPortDevice(qemuConfig.Devices, numOfPluggablePorts, memSize32bit, memSize64bit)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -1847,6 +1836,7 @@ func (q *qemu) hotplugVFIODeviceSwitchPort(ctx context.Context, device *config.V
|
||||
return fmt.Errorf("VFIO device is a PCIe device. Hotplug (%v) only supported on PCIe Root (%d) or PCIe Switch Ports (%v)",
|
||||
q.state.HotPlugVFIO, q.state.PCIeRootPort, q.state.PCIeSwitchPort)
|
||||
}
|
||||
|
||||
device.Bus = fmt.Sprintf("%s%d", pcieSwitchDownstreamPortPrefix, device.Rank)
|
||||
return q.executeVFIODeviceAdd(device)
|
||||
}
|
||||
@ -1897,11 +1887,10 @@ func (q *qemu) hotplugVFIODevice(ctx context.Context, device *config.VFIODev, op
|
||||
}
|
||||
|
||||
if op == AddDevice {
|
||||
|
||||
buf, _ := json.Marshal(device)
|
||||
q.Logger().WithFields(logrus.Fields{
|
||||
"machine-type": q.HypervisorConfig().HypervisorMachineType,
|
||||
"hotplug-vfio": q.state.HotPlugVFIO,
|
||||
"hot-plug-vfio": q.state.HotPlugVFIO,
|
||||
"pcie-root-port": q.state.PCIeRootPort,
|
||||
"pcie-switch-port": q.state.PCIeSwitchPort,
|
||||
"device-info": string(buf),
|
||||
|
@ -613,22 +613,26 @@ func newSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factor
|
||||
if err := validateHypervisorConfig(&sandboxConfig.HypervisorConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Aggregate all the container devices and update the HV config
|
||||
var devices []config.DeviceInfo
|
||||
for _, ct := range sandboxConfig.Containers {
|
||||
devices = append(devices, ct.DeviceInfos...)
|
||||
}
|
||||
sandboxConfig.HypervisorConfig.RawDevices = devices
|
||||
|
||||
// If we have a confidential guest we need to cold-plug the PCIe VFIO devices
|
||||
// until we have TDISP/IDE PCIe support.
|
||||
coldPlugVFIO := (sandboxConfig.HypervisorConfig.ColdPlugVFIO != hv.NoPort)
|
||||
var devs []config.DeviceInfo
|
||||
// Aggregate all the containner devices for hot-plug and use them to dedcue
|
||||
// the correct amount of ports to reserve for the hypervisor.
|
||||
hotPlugVFIO := (sandboxConfig.HypervisorConfig.HotPlugVFIO != hv.NoPort)
|
||||
|
||||
var vfioHotPlugDevices []config.DeviceInfo
|
||||
var vfioColdPlugDevices []config.DeviceInfo
|
||||
|
||||
for cnt, containers := range sandboxConfig.Containers {
|
||||
for dev, device := range containers.DeviceInfos {
|
||||
if coldPlugVFIO && deviceManager.IsVFIO(device.ContainerPath) {
|
||||
isVFIO := deviceManager.IsVFIO(device.ContainerPath)
|
||||
if hotPlugVFIO && isVFIO {
|
||||
vfioHotPlugDevices = append(vfioHotPlugDevices, device)
|
||||
}
|
||||
if coldPlugVFIO && isVFIO {
|
||||
device.ColdPlug = true
|
||||
devs = append(devs, device)
|
||||
vfioColdPlugDevices = append(vfioColdPlugDevices, device)
|
||||
// We need to remove the devices marked for cold-plug
|
||||
// otherwise at the container level the kata-agent
|
||||
// will try to hot-plug them.
|
||||
@ -638,6 +642,7 @@ func newSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factor
|
||||
}
|
||||
}
|
||||
}
|
||||
sandboxConfig.HypervisorConfig.VFIODevices = vfioHotPlugDevices
|
||||
|
||||
// store doesn't require hypervisor to be stored immediately
|
||||
if err = s.hypervisor.CreateVM(ctx, s.id, s.network, &sandboxConfig.HypervisorConfig); err != nil {
|
||||
@ -652,7 +657,7 @@ func newSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factor
|
||||
return s, nil
|
||||
}
|
||||
|
||||
for _, dev := range devs {
|
||||
for _, dev := range vfioColdPlugDevices {
|
||||
_, err := s.AddDevice(ctx, dev)
|
||||
if err != nil {
|
||||
s.Logger().WithError(err).Debug("Cannot cold-plug add device")
|
||||
|
@ -650,8 +650,8 @@ func TestSandboxCreateAssets(t *testing.T) {
|
||||
|
||||
// nolint: govet
|
||||
type testData struct {
|
||||
annotations map[string]string
|
||||
assetType types.AssetType
|
||||
annotations map[string]string
|
||||
}
|
||||
|
||||
tmpfile, err := os.CreateTemp("", "virtcontainers-test-")
|
||||
@ -687,50 +687,50 @@ func TestSandboxCreateAssets(t *testing.T) {
|
||||
|
||||
data := []testData{
|
||||
{
|
||||
assetType: types.FirmwareAsset,
|
||||
annotations: map[string]string{
|
||||
types.FirmwareAsset,
|
||||
map[string]string{
|
||||
annotations.FirmwarePath: filename,
|
||||
annotations.FirmwareHash: assetContentHash,
|
||||
},
|
||||
},
|
||||
{
|
||||
assetType: types.HypervisorAsset,
|
||||
annotations: map[string]string{
|
||||
types.HypervisorAsset,
|
||||
map[string]string{
|
||||
annotations.HypervisorPath: filename,
|
||||
annotations.HypervisorHash: assetContentHash,
|
||||
},
|
||||
},
|
||||
{
|
||||
assetType: types.HypervisorCtlAsset,
|
||||
annotations: map[string]string{
|
||||
types.HypervisorCtlAsset,
|
||||
map[string]string{
|
||||
annotations.HypervisorCtlPath: filename,
|
||||
annotations.HypervisorCtlHash: assetContentHash,
|
||||
},
|
||||
},
|
||||
{
|
||||
assetType: types.ImageAsset,
|
||||
annotations: map[string]string{
|
||||
types.ImageAsset,
|
||||
map[string]string{
|
||||
annotations.ImagePath: filename,
|
||||
annotations.ImageHash: assetContentHash,
|
||||
},
|
||||
},
|
||||
{
|
||||
assetType: types.InitrdAsset,
|
||||
annotations: map[string]string{
|
||||
types.InitrdAsset,
|
||||
map[string]string{
|
||||
annotations.InitrdPath: filename,
|
||||
annotations.InitrdHash: assetContentHash,
|
||||
},
|
||||
},
|
||||
{
|
||||
assetType: types.JailerAsset,
|
||||
annotations: map[string]string{
|
||||
types.JailerAsset,
|
||||
map[string]string{
|
||||
annotations.JailerPath: filename,
|
||||
annotations.JailerHash: assetContentHash,
|
||||
},
|
||||
},
|
||||
{
|
||||
assetType: types.KernelAsset,
|
||||
annotations: map[string]string{
|
||||
types.KernelAsset,
|
||||
map[string]string{
|
||||
annotations.KernelPath: filename,
|
||||
annotations.KernelHash: assetContentHash,
|
||||
},
|
||||
@ -1407,58 +1407,58 @@ func TestSandbox_Cgroups(t *testing.T) {
|
||||
|
||||
// nolint: govet
|
||||
tests := []struct {
|
||||
s *Sandbox
|
||||
name string
|
||||
s *Sandbox
|
||||
wantErr bool
|
||||
needRoot bool
|
||||
}{
|
||||
{
|
||||
name: "New sandbox",
|
||||
s: &Sandbox{},
|
||||
wantErr: true,
|
||||
needRoot: false,
|
||||
"New sandbox",
|
||||
&Sandbox{},
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
name: "New sandbox, new config",
|
||||
s: &Sandbox{config: &SandboxConfig{}},
|
||||
wantErr: false,
|
||||
needRoot: true,
|
||||
"New sandbox, new config",
|
||||
&Sandbox{config: &SandboxConfig{}},
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
name: "sandbox, container no sandbox type",
|
||||
s: &Sandbox{
|
||||
"sandbox, container no sandbox type",
|
||||
&Sandbox{
|
||||
config: &SandboxConfig{Containers: []ContainerConfig{
|
||||
{},
|
||||
}}},
|
||||
wantErr: false,
|
||||
needRoot: true,
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
name: "sandbox, container sandbox type",
|
||||
s: &Sandbox{
|
||||
"sandbox, container sandbox type",
|
||||
&Sandbox{
|
||||
config: &SandboxConfig{Containers: []ContainerConfig{
|
||||
sandboxContainer,
|
||||
}}},
|
||||
wantErr: false,
|
||||
needRoot: true,
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
name: "sandbox, empty linux json",
|
||||
s: &Sandbox{
|
||||
"sandbox, empty linux json",
|
||||
&Sandbox{
|
||||
config: &SandboxConfig{Containers: []ContainerConfig{
|
||||
emptyJSONLinux,
|
||||
}}},
|
||||
wantErr: false,
|
||||
needRoot: true,
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
name: "sandbox, successful config",
|
||||
s: &Sandbox{
|
||||
"sandbox, successful config",
|
||||
&Sandbox{
|
||||
config: &SandboxConfig{Containers: []ContainerConfig{
|
||||
successfulContainer,
|
||||
}}},
|
||||
wantErr: false,
|
||||
needRoot: true,
|
||||
false,
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@ -85,16 +85,16 @@ func TestCreateVethNetworkEndpointChooseIfaceName(t *testing.T) {
|
||||
func TestCreateVethNetworkEndpointInvalidArgs(t *testing.T) {
|
||||
// nolint: govet
|
||||
type endpointValues struct {
|
||||
ifName string
|
||||
idx int
|
||||
ifName string
|
||||
}
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
// all elements are expected to result in failure
|
||||
failingValues := []endpointValues{
|
||||
{idx: -1, ifName: "bar"},
|
||||
{idx: -1, ifName: ""},
|
||||
{-1, "bar"},
|
||||
{-1, ""},
|
||||
}
|
||||
|
||||
for _, d := range failingValues {
|
||||
|
@ -17,13 +17,13 @@ import (
|
||||
func TestVirtiofsdStart(t *testing.T) {
|
||||
// nolint: govet
|
||||
type fields struct {
|
||||
ctx context.Context
|
||||
path string
|
||||
socketPath string
|
||||
cache string
|
||||
sourcePath string
|
||||
path string
|
||||
extraArgs []string
|
||||
sourcePath string
|
||||
PID int
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
sourcePath := t.TempDir()
|
||||
@ -41,13 +41,13 @@ func TestVirtiofsdStart(t *testing.T) {
|
||||
|
||||
// nolint: govet
|
||||
tests := []struct {
|
||||
fields fields
|
||||
name string
|
||||
fields fields
|
||||
wantErr bool
|
||||
}{
|
||||
{name: "empty config", fields: fields{}, wantErr: true},
|
||||
{name: "Directory socket does not exist", fields: NoDirectorySocket, wantErr: true},
|
||||
{name: "valid config", fields: validConfig, wantErr: false},
|
||||
{"empty config", fields{}, true},
|
||||
{"Directory socket does not exist", NoDirectorySocket, true},
|
||||
{"valid config", validConfig, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -271,7 +271,7 @@ calculate_required_disk_size() {
|
||||
readonly image="$(mktemp)"
|
||||
readonly mount_dir="$(mktemp -d)"
|
||||
readonly max_tries=20
|
||||
readonly increment=100
|
||||
readonly increment=10
|
||||
|
||||
for i in $(seq 1 $max_tries); do
|
||||
local img_size="$((rootfs_size_mb + (i * increment)))"
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2018 Intel Corporation
|
||||
#
|
||||
@ -14,8 +14,6 @@
|
||||
# been specified.
|
||||
#---------------------------------------------------------------------
|
||||
|
||||
set -x
|
||||
|
||||
script_name=${0##*/}
|
||||
|
||||
arch="${3:-$(uname -m)}"
|
||||
|
Loading…
Reference in New Issue
Block a user