qemu: allow using legacy serial device for the console

This allows to get guest early boot logs which are usually
missed when virtconsole is used.
- It utilizes previous work on the govmm side:
https://github.com/kata-containers/govmm/pull/203
- unit test added

Fixes: #4237
Signed-off-by: Snir Sheriber <ssheribe@redhat.com>
This commit is contained in:
Snir Sheriber 2022-05-12 14:26:51 +03:00
parent 44814dce19
commit c67b9d2975
10 changed files with 82 additions and 19 deletions

View File

@ -389,6 +389,9 @@ valid_entropy_sources = @DEFVALIDENTROPYSOURCES@
# be default_memory. # be default_memory.
#enable_guest_swap = true #enable_guest_swap = true
# use legacy serial for guest console if available and implemented for architecture. Default false
#use_legacy_serial = true
[factory] [factory]
# VM templating support. Once enabled, new VMs are created from template # VM templating support. Once enabled, new VMs are created from template
# using vm cloning. They will share the same initial kernel, initramfs and # using vm cloning. They will share the same initial kernel, initramfs and

View File

@ -89,6 +89,7 @@ const defaultGuestSwap = false
const defaultRootlessHypervisor = false const defaultRootlessHypervisor = false
const defaultDisableSeccomp = false const defaultDisableSeccomp = false
const defaultVfioMode = "guest-kernel" const defaultVfioMode = "guest-kernel"
const defaultLegacySerial = false
var defaultSGXEPCSize = int64(0) var defaultSGXEPCSize = int64(0)

View File

@ -146,6 +146,7 @@ type hypervisor struct {
Rootless bool `toml:"rootless"` Rootless bool `toml:"rootless"`
DisableSeccomp bool `toml:"disable_seccomp"` DisableSeccomp bool `toml:"disable_seccomp"`
DisableSeLinux bool `toml:"disable_selinux"` DisableSeLinux bool `toml:"disable_selinux"`
LegacySerial bool `toml:"use_legacy_serial"`
} }
type runtime struct { type runtime struct {
@ -775,6 +776,7 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
ConfidentialGuest: h.ConfidentialGuest, ConfidentialGuest: h.ConfidentialGuest,
GuestSwap: h.GuestSwap, GuestSwap: h.GuestSwap,
Rootless: h.Rootless, Rootless: h.Rootless,
LegacySerial: h.LegacySerial,
}, nil }, nil
} }
@ -1132,6 +1134,7 @@ func GetDefaultHypervisorConfig() vc.HypervisorConfig {
GuestSwap: defaultGuestSwap, GuestSwap: defaultGuestSwap,
Rootless: defaultRootlessHypervisor, Rootless: defaultRootlessHypervisor,
DisableSeccomp: defaultDisableSeccomp, DisableSeccomp: defaultDisableSeccomp,
LegacySerial: defaultLegacySerial,
} }
} }

View File

@ -537,6 +537,9 @@ type HypervisorConfig struct {
// Disable selinux from the hypervisor process // Disable selinux from the hypervisor process
DisableSeLinux bool DisableSeLinux bool
// Use legacy serial for the guest console
LegacySerial bool
} }
// vcpu mapping from vcpu number to thread number // vcpu mapping from vcpu number to thread number

View File

@ -122,6 +122,7 @@ func newQemuArch(config HypervisorConfig) (qemuArch, error) {
disableNvdimm: config.DisableImageNvdimm, disableNvdimm: config.DisableImageNvdimm,
dax: true, dax: true,
protection: noneProtection, protection: noneProtection,
legacySerial: config.LegacySerial,
}, },
vmFactory: factory, vmFactory: factory,
} }

View File

@ -169,6 +169,7 @@ type qemuArchBase struct {
vhost bool vhost bool
disableNvdimm bool disableNvdimm bool
dax bool dax bool
legacySerial bool
} }
const ( const (
@ -318,29 +319,49 @@ func (q *qemuArchBase) memoryTopology(memoryMb, hostMemoryMb uint64, slots uint8
} }
func (q *qemuArchBase) appendConsole(_ context.Context, devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) { func (q *qemuArchBase) appendConsole(_ context.Context, devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) {
serial := govmmQemu.SerialDevice{ var serial, console govmmQemu.Device
Driver: govmmQemu.VirtioSerial, var consoleKernelParams []Param
ID: "serial0",
DisableModern: q.nestedRun, if q.legacySerial {
MaxPorts: uint(2), serial = govmmQemu.LegacySerialDevice{
Chardev: "charconsole0",
}
console = govmmQemu.CharDevice{
Driver: govmmQemu.LegacySerial,
Backend: govmmQemu.Socket,
DeviceID: "console0",
ID: "charconsole0",
Path: path,
}
consoleKernelParams = []Param{
{"console", "ttyS0"},
}
} else {
serial = govmmQemu.SerialDevice{
Driver: govmmQemu.VirtioSerial,
ID: "serial0",
DisableModern: q.nestedRun,
MaxPorts: uint(2),
}
console = govmmQemu.CharDevice{
Driver: govmmQemu.Console,
Backend: govmmQemu.Socket,
DeviceID: "console0",
ID: "charconsole0",
Path: path,
}
consoleKernelParams = []Param{
{"console", "hvc0"},
{"console", "hvc1"},
}
} }
devices = append(devices, serial) devices = append(devices, serial)
console := govmmQemu.CharDevice{
Driver: govmmQemu.Console,
Backend: govmmQemu.Socket,
DeviceID: "console0",
ID: "charconsole0",
Path: path,
}
devices = append(devices, console) devices = append(devices, console)
consoleKernelParams := []Param{
{"console", "hvc0"},
{"console", "hvc1"},
}
q.kernelParams = append(q.kernelParams, consoleKernelParams...) q.kernelParams = append(q.kernelParams, consoleKernelParams...)
return devices, nil return devices, nil

View File

@ -263,6 +263,34 @@ func TestQemuArchBaseAppendConsoles(t *testing.T) {
assert.Contains(qemuArchBase.kernelParams, Param{"console", "hvc1"}) assert.Contains(qemuArchBase.kernelParams, Param{"console", "hvc1"})
} }
func TestQemuArchBaseAppendConsolesLegacy(t *testing.T) {
var devices []govmmQemu.Device
var err error
assert := assert.New(t)
qemuArchBase := newQemuArchBase()
qemuArchBase.legacySerial = true
path := filepath.Join(filepath.Join(fs.MockRunStoragePath(), "test"), consoleSocket)
expectedOut := []govmmQemu.Device{
govmmQemu.LegacySerialDevice{
Chardev: "charconsole0",
},
govmmQemu.CharDevice{
Driver: govmmQemu.LegacySerial,
Backend: govmmQemu.Socket,
DeviceID: "console0",
ID: "charconsole0",
Path: path,
},
}
devices, err = qemuArchBase.appendConsole(context.Background(), devices, path)
assert.NoError(err)
assert.Equal(expectedOut, devices)
assert.Contains(qemuArchBase.kernelParams, Param{"console", "ttyS0"})
}
func TestQemuArchBaseAppendImage(t *testing.T) { func TestQemuArchBaseAppendImage(t *testing.T) {
var devices []govmmQemu.Device var devices []govmmQemu.Device
assert := assert.New(t) assert := assert.New(t)

View File

@ -62,6 +62,7 @@ func newQemuArch(config HypervisorConfig) (qemuArch, error) {
disableNvdimm: config.DisableImageNvdimm, disableNvdimm: config.DisableImageNvdimm,
dax: true, dax: true,
protection: noneProtection, protection: noneProtection,
legacySerial: config.LegacySerial,
}, },
} }

View File

@ -74,6 +74,7 @@ func newQemuArch(config HypervisorConfig) (qemuArch, error) {
kernelParamsDebug: kernelParamsDebug, kernelParamsDebug: kernelParamsDebug,
kernelParams: kernelParams, kernelParams: kernelParams,
protection: noneProtection, protection: noneProtection,
legacySerial: config.LegacySerial,
}, },
} }

View File

@ -66,6 +66,7 @@ func newQemuArch(config HypervisorConfig) (qemuArch, error) {
kernelParamsNonDebug: kernelParamsNonDebug, kernelParamsNonDebug: kernelParamsNonDebug,
kernelParamsDebug: kernelParamsDebug, kernelParamsDebug: kernelParamsDebug,
kernelParams: kernelParams, kernelParams: kernelParams,
legacySerial: false,
}, },
} }
// Set first bridge type to CCW // Set first bridge type to CCW