mirror of
https://github.com/vagrant-libvirt/vagrant-libvirt.git
synced 2025-02-25 18:55:27 -06:00
Adding SEV support (#1664)
Secure Encryption Virtualization is supported by libvirt and this change adds support for vagrant-libvirt to enable it. It requires a UEFI base box and needs a combination of options to be configured for it to work. Co-authored-by: PELLET Norman <norman.pellet@csem.ch> Co-authored-by: MUNTANÉ CALVO Enric <emc@csem.ch> Co-authored-by: Darragh Bailey <daragh.bailey@gmail.com> Closes: #1372
This commit is contained in:
@@ -149,6 +149,14 @@ end
|
||||
{:cpus => "2-3", :memory => "4096"}
|
||||
]
|
||||
```
|
||||
* `launchsecurity` - Configure Secure Encryption Virtualization for the guest, requires additional components to be configured to work, see [examples](./examples.html#secure-encryption-virtualization). For more information look at [libvirt documentation](https://libvirt.org/kbase/launch_security_sev.html).
|
||||
```
|
||||
libvirt.launchsecurity :type => 'sev', :cbitpos => 47, :reducedPhysBits => 1, :policy => "0x0003"
|
||||
```
|
||||
* `memtune` - Configure the memtune settings for the guest, primarily exposed to facilitate enabling Secure Encryption Virtualization. Note that when configuring `hard_limit` that the value is in kB as opposed to `libvirt.memory` which is in Mb. Additionally it must be set to be higher than `libvirt.memory`, see [libvirt documentation](https://libvirt.org/kbase/launch_security_sev.html) for details on why.
|
||||
```
|
||||
libvirt.memtune :type => "hard_limit", :value => 2500000 # Note here the value in kB (not in Mb)
|
||||
```
|
||||
* `loader` - Sets path to custom UEFI loader.
|
||||
* `kernel` - To launch the guest with a kernel residing on host filesystems.
|
||||
Equivalent to qemu `-kernel`.
|
||||
|
||||
@@ -477,6 +477,66 @@ Vagrant.configure("2") do |config|
|
||||
end
|
||||
```
|
||||
|
||||
## Secure Encryption Virtualization (SEV)
|
||||
|
||||
Secure Encryption Virtualization is supported by libvirt and by the vagrant-libvirt provider but comes with several requirements.
|
||||
|
||||
This mode has only been tested with q35 types of machines, so you'll need an UEFI boot
|
||||
|
||||
```ruby
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.provider :libvirt do |libvirt|
|
||||
libvirt.loader = "/usr/share/OVMF/OVMF_CODE.fd"
|
||||
libvirt.nvram = "/path/to/ovmf/OVMF_VARS.fd"
|
||||
libvirt.machine_type = 'pc-q35-focal'
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Read the libvirt documentaiton to understand what OVMF is and how to use it.
|
||||
|
||||
Next, you'll want to call the following methods:
|
||||
```ruby
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.provider :libvirt do |libvirt|
|
||||
libvirt.launchsecurity :type => 'sev', :cbitpos => 47, :reducedPhysBits => 1, :policy => "0x0003"
|
||||
libvirt.memtune :type => "hard_limit", :value => 2500000 # Note here the value in kB (not in Mb)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Note that the value provided in the memtune `hard_limit` is in Kb by default. It should be higher than the
|
||||
one given in `libvirt.memory` (which is in Mb, by the way) by some amount (again, check out the [https://libvirt.org/kbase/launch_security_sev.html](documentation)) to understand why.
|
||||
|
||||
It is also necessary to explicitly define the memballoon for it to accept the iommu flag.
|
||||
|
||||
```ruby
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.provider :libvirt do |libvirt|
|
||||
libvirt.memballoon_enabled = true
|
||||
libvirt.memballoon_model = 'virtio'
|
||||
libvirt.memballoon_pci_bus = '0x07'
|
||||
libvirt.memballoon_pci_slot = '0x00'
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
And finally, because the iommu flag has to be passed to the networks, you also need to set it explicitly:
|
||||
|
||||
```ruby
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.provider :libvirt do |libvirt|
|
||||
# Management network only (the NAT'ed network provided by Vagrant)
|
||||
libvirt.management_network_driver_iommu = true
|
||||
end
|
||||
# Example in defining a bridge
|
||||
config.vm.network :public_network, :dev => "br0", :bridge => "br0", :mode => "bridge", :type => "bridge", :driver_iommu => true # <== Note here the additional flag
|
||||
end
|
||||
```
|
||||
|
||||
Don't forget that you'll need an UEFI base box.
|
||||
|
||||
|
||||
## Libvirt communication channels
|
||||
|
||||
For certain functionality to be available within a guest, a private
|
||||
|
||||
@@ -38,6 +38,7 @@ module VagrantPlugins
|
||||
@features_hyperv = config.features_hyperv
|
||||
@clock_offset = config.clock_offset
|
||||
@clock_timers = config.clock_timers
|
||||
@launchsecurity_data = config.launchsecurity_data
|
||||
@shares = config.shares
|
||||
@cpu_mode = config.cpu_mode
|
||||
@cpu_model = config.cpu_model
|
||||
@@ -52,6 +53,8 @@ module VagrantPlugins
|
||||
@nested = config.nested
|
||||
@memory_size = config.memory.to_i * 1024
|
||||
@memory_backing = config.memory_backing
|
||||
@memtunes = config.memtunes
|
||||
|
||||
@management_network_mac = config.management_network_mac
|
||||
@domain_volume_cache = config.volume_cache || 'default'
|
||||
@kernel = config.kernel
|
||||
@@ -240,6 +243,10 @@ module VagrantPlugins
|
||||
@memory_backing.each do |backing|
|
||||
env[:ui].info(" -- Memory Backing: #{backing[:name]}: #{backing[:config].map { |k,v| "#{k}='#{v}'"}.join(' ')}")
|
||||
end
|
||||
|
||||
@memtunes.each do |type, options|
|
||||
env[:ui].info(" -- Memory Tuning: #{type}: #{options[:config].map { |k,v| "#{k}='#{v}'"}.join(' ')}, value: #{options[:value]}")
|
||||
end
|
||||
unless @shares.nil?
|
||||
env[:ui].info(" -- Shares: #{@shares}")
|
||||
end
|
||||
@@ -311,6 +318,10 @@ module VagrantPlugins
|
||||
env[:ui].info(" -- Disks: #{_disks_print(@disks)}")
|
||||
end
|
||||
|
||||
if not @launchsecurity_data.nil?
|
||||
env[:ui].info(" -- Launch security: #{@launchsecurity_data.map { |k, v| "#{k.to_s}=#{v}" }.join(", ")}")
|
||||
end
|
||||
|
||||
@disks.each do |disk|
|
||||
msg = " -- Disk(#{disk[:device]}): #{disk[:absolute_path]}"
|
||||
msg += ' Shared' if disk[:shareable]
|
||||
|
||||
@@ -76,6 +76,7 @@ module VagrantPlugins
|
||||
@mac = iface_configuration.fetch(:mac, false)
|
||||
@model_type = iface_configuration.fetch(:model_type, @nic_model_type)
|
||||
@driver_name = iface_configuration.fetch(:driver_name, false)
|
||||
@driver_iommu = iface_configuration.fetch(:driver_iommu, false )
|
||||
@driver_queues = iface_configuration.fetch(:driver_queues, false)
|
||||
@device_name = iface_configuration.fetch(:iface_name, false)
|
||||
@mtu = iface_configuration.fetch(:mtu, nil)
|
||||
@@ -84,12 +85,15 @@ module VagrantPlugins
|
||||
template_name = 'interface'
|
||||
@type = nil
|
||||
@udp_tunnel = nil
|
||||
|
||||
@logger.debug("Interface configuration: #{iface_configuration}")
|
||||
# Configuration for public interfaces which use the macvtap driver
|
||||
if iface_configuration[:iface_type] == :public_network
|
||||
@device = iface_configuration.fetch(:dev, 'eth0')
|
||||
@mode = iface_configuration.fetch(:mode, 'bridge')
|
||||
@type = iface_configuration.fetch(:type, 'direct')
|
||||
@model_type = iface_configuration.fetch(:model_type, @nic_model_type)
|
||||
@driver_iommu = iface_configuration.fetch(:driver_iommu, false )
|
||||
@driver_name = iface_configuration.fetch(:driver_name, false)
|
||||
@driver_queues = iface_configuration.fetch(:driver_queues, false)
|
||||
@portgroup = iface_configuration.fetch(:portgroup, nil)
|
||||
@@ -124,13 +128,14 @@ module VagrantPlugins
|
||||
}
|
||||
@tunnel_type = iface_configuration.fetch(:model_type, @nic_model_type)
|
||||
@driver_name = iface_configuration.fetch(:driver_name, false)
|
||||
@driver_iommu = iface_configuration.fetch(:driver_iommu, false )
|
||||
@driver_queues = iface_configuration.fetch(:driver_queues, false)
|
||||
template_name = 'tunnel_interface'
|
||||
@logger.info("Setting up #{@type} tunnel interface using #{@tunnel_ip} port #{@tunnel_port}")
|
||||
end
|
||||
|
||||
message = "Creating network interface eth#{@iface_number}"
|
||||
message += " connected to network #{@network_name}."
|
||||
message += " connected to network #{@network_name} based on template #{template_name}."
|
||||
if @mac
|
||||
@mac = @mac.scan(/(\h{2})/).join(':')
|
||||
message += " Using MAC address: #{@mac}"
|
||||
@@ -141,7 +146,9 @@ module VagrantPlugins
|
||||
# FIXME: all options for network driver should be hash from Vagrantfile
|
||||
driver_options = {}
|
||||
driver_options[:name] = @driver_name if @driver_name
|
||||
driver_options[:iommu] = @driver_iommu ? "on" : "off"
|
||||
driver_options[:queues] = @driver_queues if @driver_queues
|
||||
|
||||
@udp_tunnel ||= {}
|
||||
xml = if template_name == 'interface' or
|
||||
template_name == 'tunnel_interface'
|
||||
@@ -259,12 +266,15 @@ module VagrantPlugins
|
||||
xml.source(source_options) do
|
||||
xml.local(udp_tunnel) if type == 'udp'
|
||||
end
|
||||
|
||||
@logger.debug "Driver options: #{driver_options}"
|
||||
|
||||
xml.mac(address: mac) if mac
|
||||
xml.target(dev: target_dev_name(device_name, type, iface_number))
|
||||
xml.alias(name: "net#{iface_number}")
|
||||
xml.model(type: model_type.to_s)
|
||||
xml.mtu(size: Integer(mtu)) if mtu
|
||||
xml.driver(driver_options)
|
||||
xml.driver(**driver_options)
|
||||
xml.address(type: 'pci', bus: pci_bus, slot: pci_slot) if pci_bus and pci_slot
|
||||
end
|
||||
end.to_xml(
|
||||
|
||||
@@ -194,6 +194,68 @@ module VagrantPlugins
|
||||
end
|
||||
end
|
||||
|
||||
# Launch security
|
||||
launchSecurity = REXML::XPath.first(xml_descr, '/domain/launchSecurity')
|
||||
unless config.launchsecurity_data.nil?
|
||||
if launchSecurity.nil?
|
||||
@logger.debug "Launch security has been added"
|
||||
launchSecurity = REXML::Element.new('launchSecurity', REXML::XPath.first(xml_descr, '/domain'))
|
||||
descr_changed = true
|
||||
end
|
||||
|
||||
if launchSecurity.attributes['type'] != config.launchsecurity_data[:type]
|
||||
launchSecurity.attributes['type'] = config.launchsecurity_data[:type]
|
||||
descr_changed = true
|
||||
end
|
||||
|
||||
[:cbitpos, :policy, :reducedPhysBits].each do |setting|
|
||||
setting_value = config.launchsecurity_data[setting]
|
||||
element = REXML::XPath.first(launchSecurity, setting.to_s)
|
||||
if !setting_value.nil?
|
||||
if element.nil?
|
||||
element = launchSecurity.add_element(setting.to_s)
|
||||
descr_changed = true
|
||||
end
|
||||
|
||||
if element.text != setting_value
|
||||
@logger.debug "launchSecurity #{setting.to_s} config changed"
|
||||
element.text = setting_value
|
||||
descr_changed = true
|
||||
end
|
||||
else
|
||||
if !element.nil?
|
||||
launchSecurity.delete_element(setting.to_s)
|
||||
descr_changed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
controllers = REXML::XPath.each( xml_descr, '/domain/devices/controller')
|
||||
memballoon = REXML::XPath.each( xml_descr, '/domain/devices/memballoon')
|
||||
[controllers, memballoon].lazy.flat_map(&:lazy).each do |controller|
|
||||
driver_node = REXML::XPath.first(controller, 'driver')
|
||||
driver_node = controller.add_element('driver') if driver_node.nil?
|
||||
descr_changed = true if driver_node.attributes['iommu'] != 'on'
|
||||
driver_node.attributes['iommu'] = 'on'
|
||||
end
|
||||
else
|
||||
unless launchSecurity.nil?
|
||||
@logger.debug "Launch security to be deleted"
|
||||
|
||||
descr_changed = true
|
||||
|
||||
launchSecurity.parent.delete_element(launchSecurity)
|
||||
end
|
||||
|
||||
REXML::XPath.each( xml_descr, '/domain/devices/controller') do | controller |
|
||||
driver_node = REXML::XPath.first(controller, 'driver')
|
||||
if !driver_node.nil?
|
||||
descr_changed = true if driver_node.attributes['iommu']
|
||||
driver_node.attributes.delete('iommu')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Graphics
|
||||
graphics = REXML::XPath.first(xml_descr, '/domain/devices/graphics')
|
||||
if config.graphics_type != 'none'
|
||||
|
||||
@@ -67,6 +67,7 @@ module VagrantPlugins
|
||||
attr_accessor :management_network_domain
|
||||
attr_accessor :management_network_mtu
|
||||
attr_accessor :management_network_keep
|
||||
attr_accessor :management_network_driver_iommu
|
||||
|
||||
# System connection information
|
||||
attr_accessor :system_uri
|
||||
@@ -81,6 +82,7 @@ module VagrantPlugins
|
||||
attr_accessor :memory
|
||||
attr_accessor :nodeset
|
||||
attr_accessor :memory_backing
|
||||
attr_accessor :memtunes
|
||||
attr_accessor :channel
|
||||
attr_accessor :cpus
|
||||
attr_accessor :cpuset
|
||||
@@ -95,6 +97,7 @@ module VagrantPlugins
|
||||
attr_accessor :features_hyperv
|
||||
attr_accessor :clock_offset
|
||||
attr_accessor :clock_timers
|
||||
attr_accessor :launchsecurity_data
|
||||
attr_accessor :numa_nodes
|
||||
attr_accessor :loader
|
||||
attr_accessor :nvram
|
||||
@@ -243,6 +246,7 @@ module VagrantPlugins
|
||||
@management_network_domain = UNSET_VALUE
|
||||
@management_network_mtu = UNSET_VALUE
|
||||
@management_network_keep = UNSET_VALUE
|
||||
@management_network_driver_iommu = UNSET_VALUE
|
||||
|
||||
# System connection information
|
||||
@system_uri = UNSET_VALUE
|
||||
@@ -254,6 +258,7 @@ module VagrantPlugins
|
||||
@memory = UNSET_VALUE
|
||||
@nodeset = UNSET_VALUE
|
||||
@memory_backing = UNSET_VALUE
|
||||
@memtunes = {}
|
||||
@cpus = UNSET_VALUE
|
||||
@cpuset = UNSET_VALUE
|
||||
@cpu_mode = UNSET_VALUE
|
||||
@@ -267,6 +272,7 @@ module VagrantPlugins
|
||||
@features_hyperv = UNSET_VALUE
|
||||
@clock_offset = UNSET_VALUE
|
||||
@clock_timers = []
|
||||
@launchsecurity_data = UNSET_VALUE
|
||||
@numa_nodes = UNSET_VALUE
|
||||
@loader = UNSET_VALUE
|
||||
@nvram = UNSET_VALUE
|
||||
@@ -528,6 +534,37 @@ module VagrantPlugins
|
||||
config: config)
|
||||
end
|
||||
|
||||
def memtune(config={})
|
||||
if config[:type].nil?
|
||||
raise "Missing memtune type"
|
||||
end
|
||||
|
||||
unless ['hard_limit', 'soft_limit', 'swap_hard_limit'].include? config[:type]
|
||||
raise "Memtune type '#{config[:type]}' not allowed (hard_limit, soft_limit, swap_hard_limit are allowed)"
|
||||
end
|
||||
|
||||
if config[:value].nil?
|
||||
raise "Missing memtune value"
|
||||
end
|
||||
|
||||
opts = config[:options] || {}
|
||||
opts[:unit] = opts[:unit] || "KiB"
|
||||
|
||||
@memtunes[config[:type]] = { value: config[:value], config: opts }
|
||||
end
|
||||
|
||||
def launchsecurity(options = {})
|
||||
if options.fetch(:type) != 'sev'
|
||||
raise "Launch security type only supports SEV. Explicitly set 'sev' as a type"
|
||||
end
|
||||
|
||||
@launchsecurity_data = {}
|
||||
@launchsecurity_data[:type] = options[:type]
|
||||
@launchsecurity_data[:cbitpos] = options[:cbitpos] || 47
|
||||
@launchsecurity_data[:reducedPhysBits] = options[:reducedPhysBits] || 1
|
||||
@launchsecurity_data[:policy] = options[:policy] || "0x0003"
|
||||
end
|
||||
|
||||
def input(options = {})
|
||||
if options[:type].nil? || options[:bus].nil?
|
||||
raise 'Input type AND bus must be specified'
|
||||
@@ -916,6 +953,7 @@ module VagrantPlugins
|
||||
@management_network_domain = nil if @management_network_domain == UNSET_VALUE
|
||||
@management_network_mtu = nil if @management_network_mtu == UNSET_VALUE
|
||||
@management_network_keep = false if @management_network_keep == UNSET_VALUE
|
||||
@management_network_driver_iommu = false if @management_network_driver_iommu == UNSET_VALUE
|
||||
|
||||
# Domain specific settings.
|
||||
@title = '' if @title == UNSET_VALUE
|
||||
@@ -954,6 +992,7 @@ module VagrantPlugins
|
||||
@features_hyperv = [] if @features_hyperv == UNSET_VALUE
|
||||
@clock_offset = 'utc' if @clock_offset == UNSET_VALUE
|
||||
@clock_timers = [] if @clock_timers == UNSET_VALUE
|
||||
@launchsecurity_data = nil if @launchsecurity_data == UNSET_VALUE
|
||||
@numa_nodes = @numa_nodes == UNSET_VALUE ? nil : _generate_numa
|
||||
@loader = nil if @loader == UNSET_VALUE
|
||||
@nvram = nil if @nvram == UNSET_VALUE
|
||||
@@ -1224,6 +1263,8 @@ module VagrantPlugins
|
||||
c += other.floppies
|
||||
result.floppies = c
|
||||
|
||||
result.memtunes = memtunes.merge(other.memtunes)
|
||||
|
||||
result.disk_driver_opts = disk_driver_opts.merge(other.disk_driver_opts)
|
||||
|
||||
result.inputs = inputs != UNSET_VALUE ? inputs.dup + (other.inputs != UNSET_VALUE ? other.inputs : []) : other.inputs
|
||||
|
||||
@@ -45,6 +45,13 @@
|
||||
<<%= backing[:name] %> <%= backing[:config].map { |k,v| "#{k}='#{v}'"}.join(' ') %>/>
|
||||
<%- end -%>
|
||||
</memoryBacking>
|
||||
<%- end -%>
|
||||
<%- unless @memtunes.empty? -%>
|
||||
<memtune>
|
||||
<%- @memtunes.each do |name, options| -%>
|
||||
<<%= name %> <%= options[:config].map { |k,v| "#{k}='#{v}'"}.join(' ') %>><%= options[:value] %></<%= name %>>
|
||||
<%- end -%>
|
||||
</memtune>
|
||||
<%- end%>
|
||||
<%- if !@cpu_affinity.empty? || @shares -%>
|
||||
<cputune>
|
||||
@@ -229,7 +236,11 @@
|
||||
</channel>
|
||||
<%- end -%>
|
||||
<%- @inputs.each do |input| -%>
|
||||
<input type='<%= input[:type] %>' bus='<%= input[:bus] %>'/>
|
||||
<input type='<%= input[:type] %>' bus='<%= input[:bus] %>'>
|
||||
<%- unless @launchsecurity_data.nil? -%>
|
||||
<driver iommu='on' />
|
||||
<%- end -%>
|
||||
</input>
|
||||
<%- end -%>
|
||||
<%- if !@sound_type.nil? -%>
|
||||
<%# Sound device-%>
|
||||
@@ -265,6 +276,9 @@
|
||||
<%- if @rng[:model] == "random"%>
|
||||
<rng model='virtio'>
|
||||
<backend model='random'>/dev/random</backend>
|
||||
<%- unless @launchsecurity_data.nil? -%>
|
||||
<driver iommu='on' />
|
||||
<%- end -%>
|
||||
</rng>
|
||||
<%- end -%>
|
||||
<%-
|
||||
@@ -338,18 +352,32 @@
|
||||
<%- end -%>
|
||||
<%- if not @usbctl_dev.empty? -%>
|
||||
<%# USB Controller -%>
|
||||
<controller type='usb' model='<%= @usbctl_dev[:model] %>' <%= "ports=\"#{@usbctl_dev[:ports]}\" " if @usbctl_dev[:ports] %>/>
|
||||
<controller type='usb' model='<%= @usbctl_dev[:model] %>' <%= "ports=\"#{@usbctl_dev[:ports]}\" " if @usbctl_dev[:ports] %>>
|
||||
<%- unless @launchsecurity_data.nil? -%>
|
||||
<driver iommu='on' />
|
||||
<%- end -%>
|
||||
</controller>
|
||||
<%- end -%>
|
||||
<%- unless @memballoon_enabled.nil? -%>
|
||||
<%- if @memballoon_enabled -%>
|
||||
<memballoon model='<%= @memballoon_model %>'>
|
||||
<address type='pci' domain='0x0000' bus='<%= @memballoon_pci_bus %>' slot='<%= @memballoon_pci_slot %>' function='0x0'/>
|
||||
<%- unless @launchsecurity_data.nil? -%>
|
||||
<driver iommu='on' />
|
||||
<%- end -%>
|
||||
</memballoon>
|
||||
<%- else -%>
|
||||
<memballoon model='none'/>
|
||||
<%- end -%>
|
||||
<%- end -%>
|
||||
</devices>
|
||||
<%- unless @launchsecurity_data.nil? -%>
|
||||
<launchSecurity type='<%= @launchsecurity_data[:type] %>'>
|
||||
<cbitpos><%= @launchsecurity_data[:cbitpos] %></cbitpos>
|
||||
<reducedPhysBits><%= @launchsecurity_data[:reducedPhysBits] %></reducedPhysBits>
|
||||
<policy><%= @launchsecurity_data[:policy] %></policy>
|
||||
</launchSecurity>
|
||||
<%- end -%>
|
||||
<%- if not @qemu_args.empty? or not @qemu_env.empty? -%>
|
||||
<qemu:commandline>
|
||||
<%- @qemu_args.each do |arg| -%>
|
||||
|
||||
@@ -12,12 +12,15 @@
|
||||
<% end %>
|
||||
<model type='<%=@model_type%>'/>
|
||||
<% if @driver_name and @driver_queues %>
|
||||
<driver name='<%=@driver_name%>' queues='<%=@driver_queues%>'/>
|
||||
<driver <% if @driver_iommu %> iommu="on" <% end %> name='<%=@driver_name%>' queues='<%=@driver_queues%>'/>
|
||||
<% elsif @driver_queues %>
|
||||
<driver queues='<%=@driver_queues%>'/>
|
||||
<driver <% if @driver_iommu %> iommu="on" <% end %> queues='<%=@driver_queues%>'/>
|
||||
<% elsif @driver_name %>
|
||||
<driver name='<%=@driver_name%>'/>
|
||||
<driver <% if @driver_iommu %> iommu="on" <% end %> name='<%=@driver_name%>'/>
|
||||
<% elsif @driver_iommu %>
|
||||
<driver iommu='on' />
|
||||
<% end %>
|
||||
|
||||
<% if @ovs %>
|
||||
<virtualport type='openvswitch'>
|
||||
<% if @ovs_interfaceid %>
|
||||
|
||||
@@ -33,6 +33,7 @@ module VagrantPlugins
|
||||
management_network_domain = env[:machine].provider_config.management_network_domain
|
||||
management_network_mtu = env[:machine].provider_config.management_network_mtu
|
||||
management_network_keep = env[:machine].provider_config.management_network_keep
|
||||
management_network_driver_iommu = env[:machine].provider_config.management_network_driver_iommu
|
||||
logger.info "Using #{management_network_name} at #{management_network_address} as the management network #{management_network_mode} is the mode"
|
||||
|
||||
begin
|
||||
@@ -74,7 +75,7 @@ module VagrantPlugins
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
management_network_options[:driver_iommu] = management_network_driver_iommu
|
||||
|
||||
unless management_network_mac.nil?
|
||||
management_network_options[:mac] = management_network_mac
|
||||
|
||||
@@ -73,6 +73,10 @@ RSpec.configure do |config|
|
||||
|
||||
# don't run acceptance tests by default
|
||||
config.filter_run_excluding :acceptance => true
|
||||
|
||||
config.expect_with :rspec do |c|
|
||||
c.max_formatted_output_length = 2000 if c.respond_to?("max_formatted_output_length=")
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
|
||||
@@ -185,6 +185,38 @@ describe VagrantPlugins::ProviderLibvirt::Action::CreateDomain do
|
||||
end
|
||||
end
|
||||
|
||||
context 'launchSecurity' do
|
||||
let(:vagrantfile_providerconfig) do
|
||||
<<-EOF
|
||||
libvirt.launchsecurity :type => 'sev', :cbitpos => 47, :reducedPhysBits => 1, :policy => "0x0003"
|
||||
EOF
|
||||
end
|
||||
|
||||
it 'should emit the settings to the ui' do
|
||||
expect(ui).to receive(:info).with(/ -- Launch security: type=sev, cbitpos=47, reducedPhysBits=1, policy=0x0003/)
|
||||
expect(servers).to receive(:create).and_return(machine)
|
||||
|
||||
expect(subject.call(env)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'memtunes' do
|
||||
let(:vagrantfile_providerconfig) do
|
||||
<<-EOF
|
||||
libvirt.memtune :type => 'hard_limit', :value => 250000
|
||||
libvirt.memtune :type => 'soft_limit', :value => 200000
|
||||
EOF
|
||||
end
|
||||
|
||||
it 'should emit the settings to the ui' do
|
||||
expect(ui).to receive(:info).with(/ -- Memory Tuning: hard_limit: unit='KiB', value: 250000/)
|
||||
expect(ui).to receive(:info).with(/ -- Memory Tuning: soft_limit: unit='KiB', value: 200000/)
|
||||
expect(servers).to receive(:create).and_return(machine)
|
||||
|
||||
expect(subject.call(env)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'sysinfo' do
|
||||
let(:domain_xml_file) { 'sysinfo.xml' }
|
||||
let(:vagrantfile_providerconfig) do
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -58,7 +58,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -4,6 +4,7 @@ require_relative '../../spec_helper'
|
||||
|
||||
require 'vagrant-libvirt/errors'
|
||||
require 'vagrant-libvirt/action/start_domain'
|
||||
require 'vagrant-libvirt/util/unindent'
|
||||
|
||||
describe VagrantPlugins::ProviderLibvirt::Action::StartDomain do
|
||||
subject { described_class.new(app, env) }
|
||||
@@ -226,6 +227,108 @@ describe VagrantPlugins::ProviderLibvirt::Action::StartDomain do
|
||||
end
|
||||
end
|
||||
|
||||
context 'launchSecurity' do
|
||||
let(:updated_domain_xml_new_launch_security) {
|
||||
new_xml = domain_xml.dup
|
||||
new_xml.gsub!(
|
||||
/<\/devices>/,
|
||||
<<-EOF.unindent.rstrip
|
||||
</devices>
|
||||
<launchSecurity type='sev'>
|
||||
<cbitpos>47</cbitpos>
|
||||
<reducedPhysBits>1</reducedPhysBits>
|
||||
<policy>0x0003</policy>
|
||||
</launchSecurity>
|
||||
EOF
|
||||
)
|
||||
new_xml
|
||||
}
|
||||
|
||||
it 'should create if not already set' do
|
||||
machine.provider_config.launchsecurity_data = {:type => 'sev', :cbitpos => 47, :reducedPhysBits => 1, :policy => "0x0003"}
|
||||
|
||||
expect(ui).to_not receive(:warn)
|
||||
expect(connection).to receive(:define_domain).and_return(libvirt_domain)
|
||||
expect(libvirt_domain).to receive(:xml_desc).and_return(domain_xml, updated_domain_xml_new_launch_security)
|
||||
expect(libvirt_domain).to receive(:autostart=)
|
||||
expect(domain).to receive(:start)
|
||||
|
||||
expect(subject.call(env)).to be_nil
|
||||
end
|
||||
|
||||
context 'already exists' do
|
||||
let(:domain_xml_launch_security) { updated_domain_xml_new_launch_security }
|
||||
let(:updated_domain_xml_launch_security) {
|
||||
new_xml = domain_xml_launch_security.dup
|
||||
new_xml.gsub!(/<cbitpos>47/, '<cbitpos>48')
|
||||
new_xml.gsub!(/<reducedPhysBits>1/, '<reducedPhysBits>2')
|
||||
new_xml.gsub!(/<policy>0x0003/, '<policy>0x0004')
|
||||
new_xml
|
||||
}
|
||||
|
||||
|
||||
it 'should update all settings' do
|
||||
machine.provider_config.launchsecurity_data = {:type => 'sev', :cbitpos => 48, :reducedPhysBits => 2, :policy => "0x0004"}
|
||||
|
||||
expect(ui).to_not receive(:warn)
|
||||
expect(connection).to receive(:define_domain).and_return(libvirt_domain)
|
||||
expect(libvirt_domain).to receive(:xml_desc).and_return(domain_xml_launch_security, updated_domain_xml_launch_security)
|
||||
expect(libvirt_domain).to receive(:autostart=)
|
||||
expect(domain).to receive(:start)
|
||||
|
||||
expect(subject.call(env)).to be_nil
|
||||
end
|
||||
|
||||
it 'should remove if disabled' do
|
||||
machine.provider_config.launchsecurity_data = nil
|
||||
|
||||
expect(ui).to_not receive(:warn)
|
||||
expect(connection).to receive(:define_domain).and_return(libvirt_domain)
|
||||
expect(libvirt_domain).to receive(:xml_desc).and_return(domain_xml_launch_security, domain_xml)
|
||||
expect(libvirt_domain).to receive(:autostart=)
|
||||
expect(domain).to receive(:start)
|
||||
|
||||
expect(subject.call(env)).to be_nil
|
||||
end
|
||||
|
||||
context 'with controllers' do
|
||||
# makes domain_xml contain 2 controllers and memballoon
|
||||
# which should mean that launchsecurity element exists, but without
|
||||
# iommu set on controllers
|
||||
let(:test_file) { 'existing.xml' }
|
||||
let(:updated_domain_xml_launch_security_controllers) {
|
||||
new_xml = updated_domain_xml_new_launch_security.dup
|
||||
new_xml.gsub!(
|
||||
/<controller type='pci' index='0' model='pci-root'\/>/,
|
||||
"<controller type='pci' index='0' model='pci-root'><driver iommu='on'/></controller>",
|
||||
)
|
||||
new_xml.gsub!(
|
||||
/(<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'\/>)/,
|
||||
'\1<driver iommu="on"/>',
|
||||
)
|
||||
# memballoon
|
||||
new_xml.gsub!(
|
||||
/(<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'\/>)/,
|
||||
'\1<driver iommu="on"/>',
|
||||
)
|
||||
new_xml
|
||||
}
|
||||
|
||||
it 'should set driver iommu on all controllers' do
|
||||
machine.provider_config.launchsecurity_data = {:type => 'sev', :cbitpos => 47, :reducedPhysBits => 1, :policy => "0x0003"}
|
||||
|
||||
expect(ui).to_not receive(:warn)
|
||||
expect(connection).to receive(:define_domain).and_return(libvirt_domain)
|
||||
expect(libvirt_domain).to receive(:xml_desc).and_return(domain_xml_launch_security, updated_domain_xml_launch_security_controllers)
|
||||
expect(libvirt_domain).to receive(:autostart=)
|
||||
expect(domain).to receive(:start)
|
||||
|
||||
expect(subject.call(env)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'graphics' do
|
||||
context 'autoport not disabled' do
|
||||
let(:test_file) { 'existing.xml' }
|
||||
|
||||
@@ -704,6 +704,31 @@ describe VagrantPlugins::ProviderLibvirt::Config do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#launchsecurity' do
|
||||
it 'should reject invalid type' do
|
||||
expect { subject.launchsecurity(:type => 'bad') }.to raise_error("Launch security type only supports SEV. Explicitly set 'sev' as a type")
|
||||
end
|
||||
|
||||
it 'should save when valid' do
|
||||
expect(subject.launchsecurity(:type => 'sev', :cbitpos => 47, :reducedPhysBits => 1, :policy => "0x0003")).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
describe '#memtune' do
|
||||
it 'should raise an exception without type' do
|
||||
expect { subject.memtune(:value => 250000) }.to raise_error('Missing memtune type')
|
||||
end
|
||||
|
||||
it 'should raise an exception if type unrecognized' do
|
||||
expect { subject.memtune(:type => 'limit', :value => 250000) }.to raise_error('Memtune type \'limit\' not allowed (hard_limit, soft_limit, swap_hard_limit are allowed)')
|
||||
end
|
||||
|
||||
it 'should accept multiple calls' do
|
||||
expect(subject.memtune(:type => 'hard_limit', :value => 250000)).to be_truthy
|
||||
expect(subject.memtune(:type => 'soft_limit', :value => 200000)).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
def assert_invalid
|
||||
subject.finalize!
|
||||
errors = subject.validate(machine).values.first
|
||||
@@ -1045,6 +1070,27 @@ describe VagrantPlugins::ProviderLibvirt::Config do
|
||||
|
||||
subject { one.merge(two) }
|
||||
|
||||
context 'memtunes' do
|
||||
it 'should merge where type is different' do
|
||||
one.memtune(type: 'hard_limit', value: '250000')
|
||||
two.memtune(type: 'soft_limit', value: '200000')
|
||||
subject.finalize!
|
||||
expect(subject.memtunes).to eq({
|
||||
'hard_limit' => {value: '250000', config: {unit: 'KiB'}},
|
||||
'soft_limit' => {value: '200000', config: {unit: 'KiB'}},
|
||||
})
|
||||
end
|
||||
|
||||
it 'should override where type is the same' do
|
||||
one.memtune(type: 'hard_limit', value: '250000')
|
||||
two.memtune(type: 'hard_limit', value: '200000')
|
||||
subject.finalize!
|
||||
expect(subject.memtunes).to eq({
|
||||
'hard_limit' => {value: '200000', config: {unit: 'KiB'}},
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
context 'storage' do
|
||||
context 'with disks' do
|
||||
context 'assigned specific devices' do
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
<numatune>
|
||||
<memory nodeset='1-4,^3,6'/>
|
||||
</numatune>
|
||||
<memtune>
|
||||
<hard_limit unit='KiB'>250000</hard_limit>
|
||||
<soft_limit unit='KiB'>200000</soft_limit>
|
||||
</memtune>
|
||||
<cputune>
|
||||
<vcpupin vcpu="0" cpuset="0" />
|
||||
<shares>1024</shares>
|
||||
@@ -107,7 +111,8 @@
|
||||
<source path='/tmp/foo'/>
|
||||
<target type='guestfwd' address='192.0.2.42' port='4242'/>
|
||||
</channel>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'>
|
||||
<gl enable='yes'/>
|
||||
</graphics>
|
||||
@@ -154,7 +159,8 @@
|
||||
<device path='/dev/tpm0'/>
|
||||
</backend>
|
||||
</tpm>
|
||||
<controller type='usb' model='nec-xhci' ports="4" />
|
||||
<controller type='usb' model='nec-xhci' ports="4" >
|
||||
</controller>
|
||||
</devices>
|
||||
<qemu:commandline>
|
||||
<qemu:arg value='-device'/>
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -122,7 +122,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -67,6 +67,8 @@ describe 'templates/domain' do
|
||||
domain.clock_timer(name: 't2', track: 'b', tickpolicy: 'c', frequency: 'd', mode: 'e', present: 'yes')
|
||||
domain.hyperv_feature(name: 'spinlocks', state: 'on', retries: '4096')
|
||||
domain.cputopology(sockets: '1', cores: '3', threads: '2')
|
||||
domain.memtune(type: 'hard_limit', value: '250000')
|
||||
domain.memtune(type: 'soft_limit', value: '200000')
|
||||
domain.cpuaffinitiy(0 => '0')
|
||||
domain.machine_type = 'pc-compatible'
|
||||
domain.machine_arch = 'x86_64'
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<console type='pty'>
|
||||
<target port='0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='mouse' bus='ps2'>
|
||||
</input>
|
||||
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
|
||||
Reference in New Issue
Block a user