From ec480dc43848aeb20abc82e12cb673f97e6a856d Mon Sep 17 00:00:00 2001 From: Christophe de Dinechin Date: Wed, 6 Aug 2025 18:51:14 +0200 Subject: [PATCH] qemu: Respect the JSON schema for hot plug When hot-plugging CPUs on QEMU, we send a QMP command with JSON arguments. QEMU 9.2 recently became more strict[1] enforcing the JSON schema for QMP parameters. As a result, running Kata Containers with QEMU 9.2 results in a message complaining that the core-id parameter is expected to be an integer: ``` qmp hotplug cpu, cpuID=cpu-0 socketID=1, error: QMP command failed: Invalid parameter type for 'core-id', expected: integer ``` Fix that by changing the core-id, socket-id and thread-id to be integer values. [1]: https://github.com/qemu/qemu/commit/be93fd53723cbdca675bd9ed112dae5cabbe1e91 Fixes: #11633 Signed-off-by: Christophe de Dinechin --- src/runtime/pkg/govmm/qemu/qmp.go | 12 +++++------- src/runtime/pkg/govmm/qemu/qmp_test.go | 8 ++++---- src/runtime/virtcontainers/qemu.go | 16 ++++++++-------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/runtime/pkg/govmm/qemu/qmp.go b/src/runtime/pkg/govmm/qemu/qmp.go index 3b6e2c7e6b..4eafb66767 100644 --- a/src/runtime/pkg/govmm/qemu/qmp.go +++ b/src/runtime/pkg/govmm/qemu/qmp.go @@ -1257,25 +1257,23 @@ func (q *QMP) isDieIDSupported(driver string) bool { // node/board the CPU belongs to, coreID is the core number within socket the CPU belongs to, threadID is the // thread number within core the CPU belongs to. Note that socketID and threadID are not a requirement for // architecures like ppc64le. -func (q *QMP) ExecuteCPUDeviceAdd(ctx context.Context, driver, cpuID, socketID, dieID, coreID, threadID, romfile string) error { +func (q *QMP) ExecuteCPUDeviceAdd(ctx context.Context, driver, cpuID string, socketID, dieID, coreID, threadID int, romfile string) error { args := map[string]interface{}{ "driver": driver, "id": cpuID, "core-id": coreID, } - if socketID != "" && isSocketIDSupported(driver) { + if socketID >= 0 && isSocketIDSupported(driver) { args["socket-id"] = socketID } - if threadID != "" && isThreadIDSupported(driver) { + if threadID >= 0 && isThreadIDSupported(driver) { args["thread-id"] = threadID } - if q.isDieIDSupported(driver) { - if dieID != "" { - args["die-id"] = dieID - } + if dieID >= 0 && q.isDieIDSupported(driver) { + args["die-id"] = dieID } return q.executeCommand(ctx, "device_add", args, nil) diff --git a/src/runtime/pkg/govmm/qemu/qmp_test.go b/src/runtime/pkg/govmm/qemu/qmp_test.go index 06738a40d6..7aeb907e48 100644 --- a/src/runtime/pkg/govmm/qemu/qmp_test.go +++ b/src/runtime/pkg/govmm/qemu/qmp_test.go @@ -1140,10 +1140,10 @@ func TestQMPAPVFIOMediatedDeviceAdd(t *testing.T) { func TestQMPCPUDeviceAdd(t *testing.T) { drivers := []string{"host-x86_64-cpu", "host-s390x-cpu", "host-powerpc64-cpu"} cpuID := "cpu-0" - socketID := "0" - dieID := "0" - coreID := "1" - threadID := "0" + socketID := 0 + dieID := 0 + coreID := 1 + threadID := 0 for _, d := range drivers { connectedCh := make(chan *QMPVersion) disconnectedCh := make(chan struct{}) diff --git a/src/runtime/virtcontainers/qemu.go b/src/runtime/virtcontainers/qemu.go index 51a46d2729..0de579c870 100644 --- a/src/runtime/virtcontainers/qemu.go +++ b/src/runtime/virtcontainers/qemu.go @@ -2197,20 +2197,20 @@ func (q *qemu) hotplugAddCPUs(amount uint32) (uint32, error) { // CPU type, i.e host-x86_64-cpu driver := hc.Type cpuID := fmt.Sprintf("cpu-%d", len(q.state.HotpluggedVCPUs)) - socketID := fmt.Sprintf("%d", hc.Properties.Socket) - dieID := fmt.Sprintf("%d", hc.Properties.Die) - coreID := fmt.Sprintf("%d", hc.Properties.Core) - threadID := fmt.Sprintf("%d", hc.Properties.Thread) + socketID := hc.Properties.Socket + dieID := hc.Properties.Die + coreID := hc.Properties.Core + threadID := hc.Properties.Thread // If CPU type is IBM pSeries, Z or arm virt, we do not set socketID and threadID if machine.Type == "pseries" || machine.Type == QemuCCWVirtio || machine.Type == "virt" { - socketID = "" - threadID = "" - dieID = "" + socketID = -1 + threadID = -1 + dieID = -1 } if err := q.qmpMonitorCh.qmp.ExecuteCPUDeviceAdd(q.qmpMonitorCh.ctx, driver, cpuID, socketID, dieID, coreID, threadID, romFile); err != nil { - q.Logger().WithField("hotplug", "cpu").Warnf("qmp hotplug cpu, cpuID=%s socketID=%s, error: %v", cpuID, socketID, err) + q.Logger().WithField("hotplug", "cpu").Warnf("qmp hotplug cpu, cpuID=%s socketID=%d, error: %v", cpuID, socketID, err) // don't fail, let's try with other CPU continue }