From 413665213bcf938914f77472b034d91f919e334d Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 28 Nov 2022 10:19:04 +0100 Subject: [PATCH] F #5753: Two options for live memory resize This commit add a new attribute to the VM template MEMORY_RESIZE_MODE. It can be: - BALLOONING to increase/decrease the memory balloon - HOTPLUG to add/remove memory modules to the VM By default VMs will use BALLOONNING if not specified. --- share/doc/xsd/vm.xsd | 2 + src/fireedge/src/client/constants/vm.js | 1 + src/vm/VirtualMachine.cc | 40 ++++++++++++++++- src/vmm/LibVirtDriverKVM.cc | 59 ++++++++++++++++++++----- src/vmm_mad/exec/vmm_exec_kvm.conf | 3 ++ src/vmm_mad/remotes/kvm/resize | 38 +++++++++++++++- 6 files changed, 128 insertions(+), 15 deletions(-) diff --git a/share/doc/xsd/vm.xsd b/share/doc/xsd/vm.xsd index 6648b0a6c6c..51bc1260296 100644 --- a/share/doc/xsd/vm.xsd +++ b/share/doc/xsd/vm.xsd @@ -121,6 +121,8 @@ + + diff --git a/src/fireedge/src/client/constants/vm.js b/src/fireedge/src/client/constants/vm.js index fe054d33c0b..4aa1a69f7a2 100644 --- a/src/fireedge/src/client/constants/vm.js +++ b/src/fireedge/src/client/constants/vm.js @@ -181,6 +181,7 @@ import { ScheduleAction } from 'client/constants/scheduler' * @property {string} [TEMPLATE.MEMORY] - * @property {string} [TEMPLATE.MEMORY_COST] - * @property {string} [TEMPLATE.MEMORY_MAX] - + * @property {string} [TEMPLATE.MEMORY_SLOTS] - * @property {Nic|Nic[]} [TEMPLATE.NIC] - * @property {NicAlias|NicAlias[]} [TEMPLATE.NIC_ALIAS] - * @property {any} [TEMPLATE.NIC_DEFAULT] - diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index 02fa8039ab1..40b2e9b4251 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -752,6 +752,8 @@ static int set_boot_order(Template * tmpl, string& error_str) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +static int parse_memory_mode(string& mem_mode, string& error); + int VirtualMachine::insert(SqlDB * db, string& error_str) { int rc; @@ -843,13 +845,30 @@ int VirtualMachine::insert(SqlDB * db, string& error_str) user_obj_template->erase("MEMORY"); obj_template->add("MEMORY", memory); - // Check optional MEMORY_MAX attribute + // Check optional MEMORY attributes + if ( user_obj_template->get("MEMORY_RESIZE_MODE", value) ) + { + if ( parse_memory_mode(value, error_str) == -1 ) + { + goto error_mem_mode; + } + + user_obj_template->erase("MEMORY_RESIZE_MODE"); + obj_template->add("MEMORY_RESIZE_MODE", value); + } + if ( user_obj_template->get("MEMORY_MAX", ivalue) && ivalue > 0 ) { user_obj_template->erase("MEMORY_MAX"); obj_template->add("MEMORY_MAX", ivalue); } + if ( user_obj_template->get("MEMORY_SLOTS", ivalue) && ivalue > 0 ) + { + user_obj_template->erase("MEMORY_SLOTS"); + obj_template->add("MEMORY_SLOTS", ivalue); + } + if ( user_obj_template->get("CPU", fvalue) == false || fvalue <= 0 ) { goto error_cpu; @@ -1166,6 +1185,7 @@ int VirtualMachine::insert(SqlDB * db, string& error_str) error_vrouter: error_public: error_name: +error_mem_mode: error_common: NebulaLog::log("ONE",Log::ERROR, error_str); @@ -2069,6 +2089,24 @@ void VirtualMachine::reset_resize() obj_template->erase("RESIZE"); } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +static int parse_memory_mode(string& mem_mode, string& error) +{ + one_util::toupper(mem_mode); + + if (mem_mode != "BALLOONING" && mem_mode != "HOTPLUG") + { + error = "Unknown MEMORY_RESIZE_MODE: " + mem_mode; + + return -1; + } + + return 0; +} + + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/src/vmm/LibVirtDriverKVM.cc b/src/vmm/LibVirtDriverKVM.cc index 31f7bfd93d5..b49ec16f978 100644 --- a/src/vmm/LibVirtDriverKVM.cc +++ b/src/vmm/LibVirtDriverKVM.cc @@ -764,23 +764,45 @@ int LibVirtDriver::deployment_description_kvm( file << "\t\n"; // Memory must be expressed in Kb - if (vm->get_template_attribute("MEMORY",memory)) + if (!vm->get_template_attribute("MEMORY",memory)) { - bool has_memory_max = vm->get_template_attribute("MEMORY_MAX", memory_max); - has_memory_max = has_memory_max && memory < memory_max; + vm->log("VMM", Log::ERROR, "No MEMORY defined and no default provided."); + return -1; + } + + // Check for memory resize settings + string mem_mode; + + bool memory_hotplug = false; + bool has_memory_max = vm->get_template_attribute("MEMORY_MAX", memory_max); + + has_memory_max = has_memory_max && memory < memory_max; + + vm->get_template_attribute("MEMORY_RESIZE_MODE", mem_mode); - if (!has_memory_max) + if (!has_memory_max) + { + file << "\t" << memory * 1024 << "" << endl; + } + else if (mem_mode == "HOTPLUG") + { + memory_hotplug = true; + + file << "\t" << memory * 1024 << "" << endl; + + if (!topology) { - memory_max = memory; - } + int slots = 0; + get_attribute(vm, host, cluster, "MEMORY_SLOTS", slots); - file << "\t" << memory_max * 1024 << "" << endl; - file << "\t" << memory * 1024 << "" << endl; + file << "\t" << memory_max * 1024 << "" << endl; + } } - else + else //(mem_mode == "BALLOONING" || mem_mode.empty()) { - vm->log("VMM", Log::ERROR, "No MEMORY defined and no default provided."); - return -1; + file << "\t" << memory_max * 1024 << "" << endl; + file << "\t" << memory * 1024 << "" << endl; } // ------------------------------------------------------------------------ @@ -896,7 +918,7 @@ int LibVirtDriver::deployment_description_kvm( cpu_mode = "custom"; } - if ( !cpu_model.empty() || topology != 0 ) + if ( !cpu_model.empty() || topology != 0 || memory_hotplug ) { file << "\t\n"; } + if (nodes.empty() && memory_hotplug) + { + int cpus = to_i(vcpu) - 1; + if (cpus < 0) + { + cpus = 0; + } + + file << "\t\t\n\t\t\t\n\t\t" << endl; + } + vtopol(file, topology, nodes, numa_tune, mbacking); file << "\t\n"; diff --git a/src/vmm_mad/exec/vmm_exec_kvm.conf b/src/vmm_mad/exec/vmm_exec_kvm.conf index cb77dd379ea..881b0cb1861 100644 --- a/src/vmm_mad/exec/vmm_exec_kvm.conf +++ b/src/vmm_mad/exec/vmm_exec_kvm.conf @@ -20,6 +20,7 @@ # - emulator # - os [kernel,initrd,boot,root,kernel_cmd,arch,machine,sd_disk_bus] # - vcpu +# - memory_slots: number of memory slots for hotplug memory # - graphics [type, listen, passwd, keymap, random_passwd] # - features [acpi, pae, apic, hyperv, localtime, guest_agent, virtio_scsi_queues, iothreads] # - cpu_model [model] @@ -33,6 +34,8 @@ #VCPU = 1 +MEMORY_SLOTS = 16 + OS = [ ARCH = "x86_64" ] diff --git a/src/vmm_mad/remotes/kvm/resize b/src/vmm_mad/remotes/kvm/resize index 9f129da93e2..f5d4cb32a8b 100755 --- a/src/vmm_mad/remotes/kvm/resize +++ b/src/vmm_mad/remotes/kvm/resize @@ -33,6 +33,7 @@ while IFS= read -r -d '' element; do XPATH_ELEMENTS[i++]="$element" done < <($XPATH /VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/VCPU \ /VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/MEMORY \ + /VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/MEMORY_RESIZE_MODE \ /VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/RESIZE/VCPU \ /VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/RESIZE/MEMORY) @@ -40,6 +41,7 @@ unset i VCPU="${XPATH_ELEMENTS[i++]}" MEM="${XPATH_ELEMENTS[i++]}" +MEM_RESIZE_MODE="${XPATH_ELEMENTS[i++]}" VCPU_OLD="${XPATH_ELEMENTS[i++]}" MEM_OLD="${XPATH_ELEMENTS[i++]}" @@ -53,8 +55,40 @@ if [ ! -z "$MEM" -a "$MEM" -ne "$MEM_OLD" ]; then (sudo -l | grep -q sysctl) && sudo -n sysctl vm.drop_caches=3 vm.compact_memory=1 >/dev/null fi - # Add memory to VM - exec_and_log "virsh --connect ${LIBVIRT_URI} setmem ${DOMAIN} $((${MEM}*1024))" + if [ "x$MEM_RESIZE_MODE" = "xHOTPLUG" ]; then + # Hotplug + + # Extract node id from virsh dumpxml + XML_INFO=$(virsh --connect ${LIBVIRT_URI} dumpxml ${DOMAIN}) + IFS= read -r -d '' NODE_ID < <(echo "$XML_INFO" | $XPATH --subtree /domain/cpu/numa/cell/@id) + + MEM_DIFF=$(expr $MEM - $MEM_OLD) + + case $MEM_DIFF in + -*) + ACTION="detach-device" + MEM_DIFF=${MEM_DIFF#-} + ;; + *) + ACTION="attach-device" + ;; + esac + + # Create tmp file with memory device specification + TMPFILE=$(mktemp /tmp/resize.XXXXXX) + echo -e "\n\t\n\ + $MEM_DIFF\n\ + $NODE_ID\n\t\n" >$TMPFILE + + # Add memory to VM + exec_and_log "virsh --connect ${LIBVIRT_URI} ${ACTION} ${DOMAIN} ${TMPFILE} --live" + + # Cleanup + rm $TMPFILE + else + # Ballooning (default) + exec_and_log "virsh --connect ${LIBVIRT_URI} setmem ${DOMAIN} $((${MEM}*1024))" + fi # Compact memory if [ "x$CLEANUP_MEMORY_ON_STOP" = "xyes" ]; then