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