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 %>