Skip to content

Commit 8ebdbe2

Browse files
committed
feat(vm): memory hotplug (phase 1)
Simple implementation of the memory hotplug support. - Change memory setting from domain.resources to domain.memory.guest. - Support old VMs to not require reboot on module update. Signed-off-by: Ivan Mikheykin <ivan.mikheykin@flant.com>
1 parent 3b2f10d commit 8ebdbe2

File tree

2 files changed

+58
-6
lines changed

2 files changed

+58
-6
lines changed

build/components/versions.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ firmware:
33
libvirt: v10.9.0
44
edk2: stable202411
55
core:
6-
3p-kubevirt: v1.6.2-v12n.15
6+
3p-kubevirt: dvp/set-memory-limits-while-hotplugging
77
3p-containerized-data-importer: v1.60.3-v12n.16
88
distribution: 2.8.3
99
package:

images/virtualization-artifact/pkg/controller/kvbuilder/kvvm.go

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ const (
4646

4747
// GenericCPUModel specifies the base CPU model for Features and Discovery CPU model types.
4848
GenericCPUModel = "qemu64"
49+
50+
MaxMemorySizeForHotplug = 256 * 1024 * 1024 * 1024 // 256 Gi (safely limit to not overlap somewhat conservative 38 bit physical address space)
51+
EnableMemoryHotplugThreshold = 1 * 1024 * 1024 * 1024 // 1 Gi (no hotplug for VMs with less than 1Gi)
4952
)
5053

5154
type KVVMOptions struct {
@@ -269,16 +272,65 @@ func (b *KVVM) SetCPU(cores int, coreFraction string) error {
269272
return nil
270273
}
271274

275+
// SetMemory sets memory in kvvm.
276+
// There are 2 possibilities to set memory:
277+
// 1. Use domain.memory.guest field: it enabled memory hotplugging, but not set resources.limits.
278+
// 2. Explicitly set limits and requests in domain.resources. No hotplugging in this scenario.
279+
//
280+
// (1) is a new approach, and (2) should be respected for Running VMs started by previous version of the controller.
272281
func (b *KVVM) SetMemory(memorySize resource.Quantity) {
282+
// TODO delete this in the future (around version 1.12).
283+
if b.ResourceExists && isVMRunningWithMemoryResources(b.Resource) {
284+
// Keep resources as-is to not trigger a reboot.
285+
res := &b.Resource.Spec.Template.Spec.Domain.Resources
286+
if res.Requests == nil {
287+
res.Requests = make(map[corev1.ResourceName]resource.Quantity)
288+
}
289+
if res.Limits == nil {
290+
res.Limits = make(map[corev1.ResourceName]resource.Quantity)
291+
}
292+
res.Requests[corev1.ResourceMemory] = memorySize
293+
res.Limits[corev1.ResourceMemory] = memorySize
294+
return
295+
}
296+
297+
domain := &b.Resource.Spec.Template.Spec.Domain
298+
if domain.Memory == nil {
299+
domain.Memory = &virtv1.Memory{}
300+
}
301+
domain.Memory.Guest = &memorySize
302+
303+
// Enable memory hotplug if VM has enough memory (>= 1Gi).
304+
hotplugThreshold := resource.NewQuantity(EnableMemoryHotplugThreshold, resource.BinarySI)
305+
if memorySize.Cmp(*hotplugThreshold) >= 0 {
306+
maxMemory := resource.NewQuantity(MaxMemorySizeForHotplug, resource.BinarySI)
307+
domain.Memory.MaxGuest = maxMemory
308+
}
309+
310+
// Remove memory limits and requests if set by previous versions.
273311
res := &b.Resource.Spec.Template.Spec.Domain.Resources
274-
if res.Requests == nil {
275-
res.Requests = make(map[corev1.ResourceName]resource.Quantity)
312+
if res.Requests != nil {
313+
delete(res.Requests, corev1.ResourceMemory)
276314
}
277315
if res.Limits == nil {
278-
res.Limits = make(map[corev1.ResourceName]resource.Quantity)
316+
delete(res.Limits, corev1.ResourceMemory)
317+
}
318+
}
319+
320+
func isVMRunningWithMemoryResources(kvvm *virtv1.VirtualMachine) bool {
321+
if kvvm == nil {
322+
return false
279323
}
280-
res.Requests[corev1.ResourceMemory] = memorySize
281-
res.Limits[corev1.ResourceMemory] = memorySize
324+
325+
if !kvvm.Status.Created {
326+
return false
327+
}
328+
329+
res := kvvm.Spec.Template.Spec.Domain.Resources
330+
_, hasMemoryRequests := res.Requests[corev1.ResourceMemory]
331+
_, hasMemoryLimits := res.Limits[corev1.ResourceMemory]
332+
333+
return hasMemoryRequests && hasMemoryLimits
282334
}
283335

284336
func GetCPURequest(cores int, coreFraction string) (*resource.Quantity, error) {

0 commit comments

Comments
 (0)