Skip to content

Commit

Permalink
Merge b53d1ae into df1dd25
Browse files Browse the repository at this point in the history
  • Loading branch information
electrofelix committed Jun 17, 2023
2 parents df1dd25 + b53d1ae commit 5366c18
Show file tree
Hide file tree
Showing 15 changed files with 415 additions and 98 deletions.
14 changes: 6 additions & 8 deletions docs/configuration.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,7 @@ end
Note: for discard to work, you will likely also need to set `disk_bus = 'scsi'`
* `:detect_zeroes` - Controls whether to detect zero write requests. The value can be "off", "on" or "unmap".
* `address_type` - Address type of disk device to emulate. If unspecified, Libvirt uses a sensible default.
* `nic_model_type` - parameter specifies the model of the network adapter when
you create a domain value by default virtio KVM believe possible values, see
the [documentation for Libvirt](https://libvirt.org/formatdomain.html#setting-the-nic-model).
* `nic_model_type` - parameter specifies the model of the network adapter when you create a domain, default is 'virtio'. For possible values, see the [documentation for Libvirt](https://libvirt.org/formatdomain.html#setting-the-nic-model).
* `shares` - Proportional weighted share for the domain relative to others. For more details see [documentation](https://libvirt.org/formatdomain.html#cpu-tuning).
* `memory` - Amount of memory in MBytes. Defaults to 512 if not set.
* `cpus` - Number of virtual cpus. Defaults to 1 if not set.
Expand Down Expand Up @@ -498,12 +496,12 @@ starts with `libvirt__` string. Here is a list of those options:
failures](https://github.com/vagrant-libvirt/vagrant-libvirt/pull/498). Note
that you cannot use names reserved for libvirt's usage based on [documentation](
https://libvirt.org/formatdomain.html#overriding-the-target-element).
* `:mac` - MAC address for the interface. *Note: specify this in lowercase
* `:libvirt__mac` - MAC address for the interface. *Note: specify this in lowercase
since Vagrant network scripts assume it will be!*
* `:libvirt__mtu` - MTU size for the Libvirt network, if not defined, the
created network will use the Libvirt default (1500). VMs still need to set the
MTU accordingly.
* `:model_type` - parameter specifies the model of the network adapter when you
* `:libvirt__model_type` - parameter specifies the model of the network adapter when you
create a domain value by default virtio KVM believe possible values, see the
documentation for Libvirt
* `:libvirt__driver_name` - Define which network driver to use. [More
Expand All @@ -513,8 +511,8 @@ starts with `libvirt__` string. Here is a list of those options:
info](http://www.linux-kvm.org/page/Multiqueue)
* `:autostart` - Automatic startup of network by the Libvirt daemon.
If not specified the default is 'false'.
* `:bus` - The bus of the PCI device. Both :bus and :slot have to be defined.
* `:slot` - The slot of the PCI device. Both :bus and :slot have to be defined.
* `:libvirt__bus` - The bus of the PCI device. Both :bus and :slot have to be defined.
* `:libvirt__slot` - The slot of the PCI device. Both :bus and :slot have to be defined.
* `:libvirt__always_destroy` - Allow domains that use but did not create a
network to destroy it when the domain is destroyed (default: `true`). Set to
`false` to only allow the domain that created the network to destroy it.
Expand Down Expand Up @@ -592,7 +590,7 @@ used by this network are configurable at the provider level.
* `management_network_keep` - Starting from version *0.7.0*, *always_destroy* is set to *true* by default for any network.
This option allows to change this behaviour for the management network.
* `management_network_iface_name` - Allow controlling of the network device name that appears on the host for the management network, same as `:libvirt__iface_name` for public and private network definitions. (unreleased).
* `management_network_model_type` - Model of the network adapter to use for the management interface. Default is 'virtio'.
* `management_network_model_type` - Model of the network adapter to use for the management interface. Default is `nic_model_type`, which in turn defaults to 'virtio'.

You may wonder how vagrant-libvirt knows the IP address a VM received. Libvirt
doesn't provide a standard way to find out the IP address of a running domain.
Expand Down
70 changes: 2 additions & 68 deletions lib/vagrant-libvirt/action/create_network_interfaces.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# frozen_string_literal: true

require 'log4r'
require 'vagrant/util/network_ip'
require 'vagrant/util/scoped_hash_override'

require 'vagrant-libvirt/util/erb_template'
require 'vagrant-libvirt/util/network_util'
Expand All @@ -15,14 +13,12 @@ module Action
class CreateNetworkInterfaces
include VagrantPlugins::ProviderLibvirt::Util::ErbTemplate
include VagrantPlugins::ProviderLibvirt::Util::NetworkUtil
include Vagrant::Util::NetworkIP
include Vagrant::Util::ScopedHashOverride

def initialize(app, env)
@logger = Log4r::Logger.new('vagrant_libvirt::action::create_network_interfaces')
@management_network_name = env[:machine].provider_config.management_network_name
config = env[:machine].provider_config
@nic_model_type = config.nic_model_type || 'virtio'
@nic_model_type = config.nic_model_type
@nic_adapter_count = config.nic_adapter_count
@app = app
end
Expand All @@ -39,34 +35,7 @@ def call(env)
end

# Setup list of interfaces before creating them.
adapters = []

# Vagrant gives you adapter 0 by default
# Assign interfaces to slots.
configured_networks(env[:machine], @logger).each do |options|
# don't need to create interface for this type
next if options[:iface_type] == :forwarded_port

# TODO: fill first ifaces with adapter option specified.
if options[:adapter]
if adapters[options[:adapter]]
raise Errors::InterfaceSlotNotAvailable
end

free_slot = options[:adapter].to_i
@logger.debug "Using specified adapter slot #{free_slot}"
else
free_slot = find_empty(adapters)
@logger.debug "Adapter not specified so found slot #{free_slot}"
raise Errors::InterfaceSlotExhausted if free_slot.nil?
end

# We have slot for interface, fill it with interface configuration.
adapters[free_slot] = options
adapters[free_slot][:network_name] = interface_network(
env[:machine].provider.driver, adapters[free_slot]
)
end
adapters = network_interfaces(env[:machine], @logger)

# Create each interface as new domain device.
@macs_per_network = Hash.new(0)
Expand Down Expand Up @@ -286,41 +255,6 @@ def interface_xml(type, source_options, mac, device_name,
Nokogiri::XML::Node::SaveOptions::FORMAT
)
end

def find_empty(array, start = 0, stop = @nic_adapter_count)
(start..stop).each do |i|
return i unless array[i]
end
nil
end

# Return network name according to interface options.
def interface_network(driver, options)
# no need to get interface network for tcp tunnel config
return 'tunnel_interface' if options.fetch(:tunnel_type, nil)

if options[:network_name]
@logger.debug 'Found network by name'
return options[:network_name]
end

# Get list of all (active and inactive) Libvirt networks.
available_networks = libvirt_networks(driver)

return 'public' if options[:iface_type] == :public_network

if options[:ip]
address = network_address(options[:ip], options[:netmask])
available_networks.each do |network|
if address == network[:network_address]
@logger.debug 'Found network by ip'
return network[:name]
end
end
end

raise Errors::NetworkNotAvailableError, network_name: options[:ip]
end
end
end
end
Expand Down
46 changes: 40 additions & 6 deletions lib/vagrant-libvirt/action/start_domain.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@
require 'rexml/formatters/pretty'
require 'rexml/xpath'

require 'vagrant-libvirt/util/network_util'
require 'vagrant-libvirt/util/xml'

module VagrantPlugins
module ProviderLibvirt
module Action
# Just start the domain.
class StartDomain
include VagrantPlugins::ProviderLibvirt::Util::NetworkUtil

def initialize(app, _env)
def initialize(app, env)
@logger = Log4r::Logger.new('vagrant_libvirt::action::start_domain')
config = env[:machine].provider_config
@nic_adapter_count = config.nic_adapter_count
@app = app
end

Expand Down Expand Up @@ -68,14 +72,44 @@ def call(env)
end

# Interface type
unless config.nic_model_type.nil?
REXML::XPath.each(xml_descr, '/domain/devices/interface/model') do |iface_model|
if iface_model.attributes['type'] != config.nic_model_type
@logger.debug "network type updated from '#{iface_model.attributes['type']}' to '#{config.nic_model_type}'"
adapters = network_interfaces(env[:machine], @logger)
index = 0
REXML::XPath.each(xml_descr, '/domain/devices/interface') do |iface|
# initial config defaults
nic_model_type = index == 0 && config.mgmt_attach ? config.management_network_model_type : config.nic_model_type
driver_iommu = index == 0 && config.mgmt_attach ? config.management_network_driver_iommu : false
# resolve per adapter option
if index < adapters.length
nic_model_type = adapters[index].fetch(:model_type, nic_model_type)
driver_iommu = adapters[index].fetch(:driver_iommu, driver_iommu )
end

iface_model = iface.elements['model']
if iface_model.attributes['type'] != nic_model_type
@logger.debug "network type updated from '#{iface_model.attributes['type']}' to '#{nic_model_type}'"
descr_changed = true
iface_model.attributes['type'] = nic_model_type
end

iface_driver = iface.elements['driver'] || REXML::Element.new('driver', iface)

if nic_model_type == 'virtio'
iommu = driver_iommu ? 'on': 'off'
if !iface_driver.attributes['iommu'].nil? && !driver_iommu.nil? && iface_driver.attributes['iommu'] != iommu
descr_changed = true
iface_model.attributes['type'] = config.nic_model_type
iface_driver.attributes['iommu'] = iommu
end
else
if !iface_driver.nil?
descr_changed = true if iface_driver.attributes['iommu']
iface_driver.attributes.delete('iommu')
end
end
iface.delete_element(iface_driver) if iface_driver.attributes.empty?
index += 1
end
if adapters.length != index
env[:ui].warn("number of network adapters in current config (#{adapters.length}) is different to attached interfaces (#{index}), may have incorrectly updated")
end

# vCpu count
Expand Down
34 changes: 18 additions & 16 deletions lib/vagrant-libvirt/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -962,21 +962,6 @@ def finalize!
@snapshot_pool_name = @storage_pool_name if @snapshot_pool_name == UNSET_VALUE
@storage_pool_path = nil if @storage_pool_path == UNSET_VALUE
@random_hostname = false if @random_hostname == UNSET_VALUE
@management_network_device = 'virbr0' if @management_network_device == UNSET_VALUE
@management_network_name = 'vagrant-libvirt' if @management_network_name == UNSET_VALUE
@management_network_address = '192.168.121.0/24' if @management_network_address == UNSET_VALUE
@management_network_mode = 'nat' if @management_network_mode == UNSET_VALUE
@management_network_mac = nil if @management_network_mac == UNSET_VALUE
@management_network_guest_ipv6 = 'yes' if @management_network_guest_ipv6 == UNSET_VALUE
@management_network_autostart = false if @management_network_autostart == UNSET_VALUE
@management_network_pci_bus = nil if @management_network_pci_bus == UNSET_VALUE
@management_network_pci_slot = nil if @management_network_pci_slot == UNSET_VALUE
@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
@management_network_iface_name = nil if @management_network_iface_name == UNSET_VALUE
@management_network_model_type = 'virtio' if @management_network_model_type == UNSET_VALUE

# Domain specific settings.
@title = '' if @title == UNSET_VALUE
Expand Down Expand Up @@ -1035,7 +1020,7 @@ def finalize!
end
@disk_address_type = nil if @disk_address_type == UNSET_VALUE
@disk_driver_opts = {} if @disk_driver_opts == UNSET_VALUE
@nic_model_type = nil if @nic_model_type == UNSET_VALUE
@nic_model_type = 'virtio' if @nic_model_type == UNSET_VALUE
@nested = false if @nested == UNSET_VALUE
@volume_cache = nil if @volume_cache == UNSET_VALUE
@kernel = nil if @kernel == UNSET_VALUE
Expand Down Expand Up @@ -1150,6 +1135,23 @@ def finalize!

@serials = [{:type => 'pty', :source => nil}] if @serials == UNSET_VALUE

# management network options
@management_network_device = 'virbr0' if @management_network_device == UNSET_VALUE
@management_network_name = 'vagrant-libvirt' if @management_network_name == UNSET_VALUE
@management_network_address = '192.168.121.0/24' if @management_network_address == UNSET_VALUE
@management_network_mode = 'nat' if @management_network_mode == UNSET_VALUE
@management_network_mac = nil if @management_network_mac == UNSET_VALUE
@management_network_guest_ipv6 = 'yes' if @management_network_guest_ipv6 == UNSET_VALUE
@management_network_autostart = false if @management_network_autostart == UNSET_VALUE
@management_network_pci_bus = nil if @management_network_pci_bus == UNSET_VALUE
@management_network_pci_slot = nil if @management_network_pci_slot == UNSET_VALUE
@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
@management_network_iface_name = nil if @management_network_iface_name == UNSET_VALUE
@management_network_model_type = @nic_model_type if @management_network_model_type == UNSET_VALUE

@host_device_exclude_prefixes = ['docker', 'macvtap', 'virbr', 'vnet'] if @host_device_exclude_prefixes == UNSET_VALUE
end

Expand Down
69 changes: 69 additions & 0 deletions lib/vagrant-libvirt/util/network_util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'ipaddr'
require 'nokogiri'
require 'vagrant/util/network_ip'
require 'vagrant/util/scoped_hash_override'

class IPAddr
def get_mask
Expand All @@ -17,6 +18,39 @@ module ProviderLibvirt
module Util
module NetworkUtil
include Vagrant::Util::NetworkIP
include Vagrant::Util::ScopedHashOverride

def network_interfaces(machine, logger)
# Setup list of interfaces before creating them.
adapters = []

# Vagrant gives you adapter 0 by default
# Assign interfaces to slots.
configured_networks(machine, logger).each do |options|
# don't need to create interface for this type
next if options[:iface_type] == :forwarded_port

# TODO: fill first ifaces with adapter option specified.
if options[:adapter]
if adapters[options[:adapter]]
raise Errors::InterfaceSlotNotAvailable
end

free_slot = options[:adapter].to_i
@logger.debug "Using specified adapter slot #{free_slot}"
else
free_slot = find_empty(adapters)
@logger.debug "Adapter not specified so found slot #{free_slot}"
raise Errors::InterfaceSlotExhausted if free_slot.nil?
end

# We have slot for interface, fill it with interface configuration.
adapters[free_slot] = options
adapters[free_slot][:network_name] = interface_network(machine.provider.driver, adapters[free_slot])
end

adapters
end

def configured_networks(machine, logger)
qemu_use_session = machine.provider_config.qemu_use_session
Expand Down Expand Up @@ -198,6 +232,41 @@ def libvirt_networks(driver)

libvirt_networks
end

def find_empty(array, start = 0, stop = @nic_adapter_count)
(start..stop).each do |i|
return i unless array[i]
end
nil
end

# Return network name according to interface options.
def interface_network(driver, options)
# no need to get interface network for tcp tunnel config
return 'tunnel_interface' if options.fetch(:tunnel_type, nil)

if options[:network_name]
@logger.debug 'Found network by name'
return options[:network_name]
end

# Get list of all (active and inactive) Libvirt networks.
available_networks = libvirt_networks(driver)

return 'public' if options[:iface_type] == :public_network

if options[:ip]
address = network_address(options[:ip], options[:netmask])
available_networks.each do |network|
if address == network[:network_address]
@logger.debug 'Found network by ip'
return network[:name]
end
end
end

raise Errors::NetworkNotAvailableError, network_name: options[:ip]
end
end
end
end
Expand Down

0 comments on commit 5366c18

Please sign in to comment.