diff --git a/README.md b/README.md
index 396a8a2..14ed0cd 100644
--- a/README.md
+++ b/README.md
@@ -300,7 +300,16 @@ end
* `cpu_fallback` - Whether to allow libvirt to fall back to a CPU model close
to the specified model if features in the guest CPU are not supported on the
host. Defaults to 'allow' if not set. Allowed values: `allow`, `forbid`.
-* `numa_nodes` - Number of NUMA nodes on guest. Must be a factor of `cpu`.
+* `numa_nodes` - Specify an array of NUMA nodes for the guest. The syntax is similar to what would be set in the domain XML. `memory` must be in MB. Symmetrical and asymmetrical topologies are supported but make sure your total count of defined CPUs adds up to `v.cpus`.
+
+ The sum of all the memory defined here will act as your total memory for your guest VM. **This sum will override what is set in `v.memory`**
+ ```
+ v.cpus = 4
+ v.numa_nodes = [
+ {:cpus => "0-1", :memory => "1024"},
+ {:cpus => "2-3", :memory => "4096"}
+ ]
+ ```
* `loader` - Sets path to custom UEFI loader.
* `volume_cache` - Controls the cache mechanism. Possible values are "default",
"none", "writethrough", "writeback", "directsync" and "unsafe". [See
diff --git a/lib/vagrant-libvirt/action/start_domain.rb b/lib/vagrant-libvirt/action/start_domain.rb
index 0a75bd2..7461905 100644
--- a/lib/vagrant-libvirt/action/start_domain.rb
+++ b/lib/vagrant-libvirt/action/start_domain.rb
@@ -23,9 +23,13 @@ module VagrantPlugins
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
- if config.memory.to_i * 1024 != libvirt_domain.max_memory
- libvirt_domain.max_memory = config.memory.to_i * 1024
- libvirt_domain.memory = libvirt_domain.max_memory
+ # libvirt API doesn't support modifying memory on NUMA enabled CPUs
+ # http://libvirt.org/git/?p=libvirt.git;a=commit;h=d174394105cf00ed266bf729ddf461c21637c736
+ if config.numa_nodes == nil
+ if config.memory.to_i * 1024 != libvirt_domain.max_memory
+ libvirt_domain.max_memory = config.memory.to_i * 1024
+ libvirt_domain.memory = libvirt_domain.max_memory
+ end
end
begin
# XML definition manipulation
@@ -124,7 +128,7 @@ module VagrantPlugins
cpu.delete_element(svm_feature)
end
end
- else
+ elsif config.numa_nodes == nil
unless cpu.elements.to_a.empty?
descr_changed = true
cpu.elements.each do |elem|
diff --git a/lib/vagrant-libvirt/config.rb b/lib/vagrant-libvirt/config.rb
index a068cfa..d75a08c 100644
--- a/lib/vagrant-libvirt/config.rb
+++ b/lib/vagrant-libvirt/config.rb
@@ -279,26 +279,27 @@ module VagrantPlugins
end
def _generate_numa
- raise 'NUMA nodes must be a factor of CPUs' if @cpus % @numa_nodes != 0
+ @numa_nodes.collect { |x|
+ # Perform some validation of cpu values
+ unless x[:cpus] =~ /^\d+-\d+$/
+ raise 'numa_nodes[:cpus] must be in format "integer-integer"'
+ end
- if @memory % @numa_nodes != 0
- raise 'NUMA nodes must be a factor of memory'
+ # Convert to KiB
+ x[:memory] = x[:memory].to_i * 1024
+ }
+
+ # Grab the value of the last @numa_nodes[:cpus] and verify @cpus matches
+ # Note: [:cpus] is zero based and @cpus is not, so we need to +1
+ last_cpu = @numa_nodes.last[:cpus]
+ last_cpu = last_cpu.scan(/\d+$/)[0]
+ last_cpu = last_cpu.to_i + 1
+
+ if @cpus != last_cpu.to_i
+ raise 'The total number of numa_nodes[:cpus] must equal config.cpus'
end
- numa = []
-
- (1..@numa_nodes).each do |node|
- numa_cpu_start = (@cpus / @numa_nodes) * (node - 1)
- numa_cpu_end = (@cpus / @numa_nodes) * node - 1
- numa_cpu = Array(numa_cpu_start..numa_cpu_end).join(',')
- numa_mem = @memory / @numa_nodes
-
- numa.push(id: node,
- cpu: numa_cpu,
- mem: numa_mem)
- end
-
- @numa_nodes = numa
+ @numa_nodes
end
def cpu_feature(options = {})
diff --git a/lib/vagrant-libvirt/templates/domain.xml.erb b/lib/vagrant-libvirt/templates/domain.xml.erb
index b216300..7fd991e 100644
--- a/lib/vagrant-libvirt/templates/domain.xml.erb
+++ b/lib/vagrant-libvirt/templates/domain.xml.erb
@@ -15,14 +15,13 @@
<% @cpu_features.each do |cpu_feature| %>
<% end %>
- <% else %>
- <% if @numa_nodes %>
-
- <% @numa_nodes.each do |node| %>
- |
- <% end %>
-
- <% end %>
+ <% end %>
+ <% if @numa_nodes %>
+
+ <% @numa_nodes.each_with_index do |node, index| %>
+ |
+ <% end %>
+
<% end %>