Skip to content

Commit

Permalink
F #5753: Two options for live memory resize
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rsmontero committed Nov 28, 2022
1 parent b64d9d7 commit 4136652
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 15 deletions.
2 changes: 2 additions & 0 deletions share/doc/xsd/vm.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@
<xs:element name="MEMORY" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="MEMORY_COST" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="MEMORY_MAX" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="MEMORY_SLOTS" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="MEMORY_RESIZE_MODE" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="NIC" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
Expand Down
1 change: 1 addition & 0 deletions src/fireedge/src/client/constants/vm.js
Original file line number Diff line number Diff line change
Expand Up @@ -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] -
Expand Down
40 changes: 39 additions & 1 deletion src/vm/VirtualMachine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}


/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

Expand Down
59 changes: 47 additions & 12 deletions src/vmm/LibVirtDriverKVM.cc
Original file line number Diff line number Diff line change
Expand Up @@ -764,23 +764,45 @@ int LibVirtDriver::deployment_description_kvm(
file << "\t</cputune>\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>" << memory * 1024 << "</memory>" << endl;
}
else if (mem_mode == "HOTPLUG")
{
memory_hotplug = true;

file << "\t<memory>" << memory * 1024 << "</memory>" << endl;

if (!topology)
{
memory_max = memory;
}
int slots = 0;
get_attribute(vm, host, cluster, "MEMORY_SLOTS", slots);

file << "\t<memory>" << memory_max * 1024 << "</memory>" << endl;
file << "\t<currentMemory>" << memory * 1024 << "</currentMemory>" << endl;
file << "\t<maxMemory slots='" << slots
<< "'>" << memory_max * 1024 << "</maxMemory>" << 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>" << memory_max * 1024 << "</memory>" << endl;
file << "\t<currentMemory>" << memory * 1024 << "</currentMemory>" << endl;
}

// ------------------------------------------------------------------------
Expand Down Expand Up @@ -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<cpu";

Expand All @@ -915,6 +937,19 @@ int LibVirtDriver::deployment_description_kvm(
file << ">\n";
}

if (nodes.empty() && memory_hotplug)
{
int cpus = to_i(vcpu) - 1;
if (cpus < 0)
{
cpus = 0;
}

file << "\t\t<numa>\n\t\t\t<cell id='0' cpus='0-" << cpus
<< "' memory=" << one_util::escape_xml_attr(memory * 1024)
<< " unit='KiB'/>\n\t\t</numa>" << endl;
}

vtopol(file, topology, nodes, numa_tune, mbacking);

file << "\t</cpu>\n";
Expand Down
3 changes: 3 additions & 0 deletions src/vmm_mad/exec/vmm_exec_kvm.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -33,6 +34,8 @@

#VCPU = 1

MEMORY_SLOTS = 16

OS = [
ARCH = "x86_64"
]
Expand Down
38 changes: 36 additions & 2 deletions src/vmm_mad/remotes/kvm/resize
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ 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)

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++]}"

Expand All @@ -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 "<memory model='dimm'>\n\t<target>\n\
<size unit='MiB'>$MEM_DIFF</size>\n\
<node>$NODE_ID</node>\n\t</target>\n</memory>" >$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
Expand Down

0 comments on commit 4136652

Please sign in to comment.