Merge pull request #455 from skamithi/mcast_and_tcp_tunnel_support

UDP/TCP/Mcast tunnel support for point-2-point VM connections
This commit is contained in:
Dmitry Vasilets 2015-09-09 08:52:03 +02:00
commit 4a8b88fc87
7 changed files with 81 additions and 49 deletions

View File

@ -198,7 +198,7 @@ Vagrant.configure("2") do |config|
The following example shows part of a Vagrantfile that enables the VM to The following example shows part of a Vagrantfile that enables the VM to
boot from a network interface first and a hard disk second. This could be boot from a network interface first and a hard disk second. This could be
used to run VMs that are meant to be a PXE booted machines. Be aware that used to run VMs that are meant to be a PXE booted machines. Be aware that
if `hd` is not specified as a boot option, it will never be tried. if `hd` is not specified as a boot option, it will never be tried.
```ruby ```ruby
@ -218,11 +218,16 @@ Vagrant.configure("2") do |config|
Networking features in the form of `config.vm.network` support private networks Networking features in the form of `config.vm.network` support private networks
concept. It supports both the virtual network switch routing types and the point to concept. It supports both the virtual network switch routing types and the point to
point Guest OS to Guest OS setting using TCP tunnel interfaces. point Guest OS to Guest OS setting using UDP/Mcast/TCP tunnel interfaces.
http://wiki.libvirt.org/page/VirtualNetworking http://wiki.libvirt.org/page/VirtualNetworking
https://libvirt.org/formatdomain.html#elementsNICSTCP https://libvirt.org/formatdomain.html#elementsNICSTCP
http://libvirt.org/formatdomain.html#elementsNICSMulticast
http://libvirt.org/formatdomain.html#elementsNICSUDP _(in libvirt v1.2.20 and higher)_
Public Network interfaces are currently implemented using the macvtap driver. The macvtap Public Network interfaces are currently implemented using the macvtap driver. The macvtap
driver is only available with the Linux Kernel version >= 2.6.24. See the following libvirt driver is only available with the Linux Kernel version >= 2.6.24. See the following libvirt
documentation for the details of the macvtap usage. documentation for the details of the macvtap usage.
@ -242,18 +247,18 @@ An examples of network interface definitions:
# Guest 1 # Guest 1
config.vm.define :test_vm1 do |test_vm1| config.vm.define :test_vm1 do |test_vm1|
test_vm1.vm.network :private_network, test_vm1.vm.network :private_network,
:libvirt__tcp_tunnel_type => 'server', :libvirt__tunnel_type => 'server',
# default is 127.0.0.1 if omitted # default is 127.0.0.1 if omitted
# :libvirt__tcp_tunnel_ip => '127.0.0.1', # :libvirt__tunnel_ip => '127.0.0.1',
:libvirt__tcp_tunnel_port => '11111' :libvirt__tunnel_port => '11111'
# Guest 2 # Guest 2
config.vm.define :test_vm2 do |test_vm2| config.vm.define :test_vm2 do |test_vm2|
test_vm2.vm.network :private_network, test_vm2.vm.network :private_network,
:libvirt__tcp_tunnel_type => 'client', :libvirt__tunnel_type => 'client',
# default is 127.0.0.1 if omitted # default is 127.0.0.1 if omitted
# :libvirt__tcp_tunnel_ip => '127.0.0.1', # :libvirt__tunnel_ip => '127.0.0.1',
:libvirt__tcp_tunnel_port => '11111' :libvirt__tunnel_port => '11111'
# Public Network # Public Network
@ -317,15 +322,25 @@ starts with 'libvirt__' string. Here is a list of those options:
* `:libvirt__forward_device` - Name of interface/device, where network should * `:libvirt__forward_device` - Name of interface/device, where network should
be forwarded (NATed or routed). Used only when creating new network. By be forwarded (NATed or routed). Used only when creating new network. By
default, all physical interfaces are used. default, all physical interfaces are used.
* `:libvirt_tcp_tunnel_type` - Set it to "server" or "client" to enable TCP * `:libvirt__tunnel_type` - Set to 'udp' if using UDP unicast tunnel mode (libvirt v1.2.20 or higher).
tunnel interface configuration. This configuration type uses TCP tunnels to Set this to either "server" or "client" for tcp tunneling. Set this to 'mcast' if using multicast
tunneling. This configuration type uses tunnels to
generate point to point connections between Guests. Useful for Switch VMs like generate point to point connections between Guests. Useful for Switch VMs like
Cumulus Linux. No virtual switch setting like "libvirt__network_name" applies with TCP Cumulus Linux. No virtual switch setting like "libvirt__network_name" applies with
tunnel interfaces and will be ignored if configured. tunnel interfaces and will be ignored if configured.
* `:libvirt_tcp_tunnel_ip` - Sets the source IP of the TCP Tunnel interface. By * `:libvirt__tunnel_ip` - Sets the source IP of the libvirt tunnel interface. By
default this is `127.0.0.1` default this is `127.0.0.1` for TCP and UDP tunnels and `239.255.1.1` for Multicast
* `:libvirt_tcp_tunnel_port` - Sets the TCP Tunnel interface port that either tunnels. It populates the address field in the `<source address="XXX">` of the
the client will connect to, or the server will listen on. interface xml configuration.
* `:libvirt__tunnel_port` - Sets the source port the tcp/udp/mcast tunnel
with use. This port information is placed in the `<source port=XXX/>` section of
interface xml configuration.
* `:libvirt__tunnel_local_port` - Sets the local port used by the udp tunnel
interface type. It populates the port field in the `<local port=XXX">` section of the
interface xml configuration. _(This feature only works in libvirt 1.2.20 and higher)_
* `:libvirt__tunnel_local_ip` - Sets the local IP used by the udp tunnel
interface type. It populates the ip entry of the `<local address=XXX">` section of
the interface xml configuration. _(This feature only works in libvirt 1.2.20 and higher)_
* `:mac` - MAC address for the interface. * `:mac` - MAC address for the interface.
* `: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 * `: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
@ -435,7 +450,7 @@ There is support for PXE booting VMs with no disks as well as PXE booting VMs wi
* No provisioning scripts are ran * No provisioning scripts are ran
* No network configuration is being applied to the VM * No network configuration is being applied to the VM
* No SSH connection can be made * No SSH connection can be made
* ```vagrant halt``` will only work cleanly if the VM handles ACPI shutdown signals * ```vagrant halt``` will only work cleanly if the VM handles ACPI shutdown signals
In short, VMs without a box can be created, halted and destroyed but all other functionality cannot be used. In short, VMs without a box can be created, halted and destroyed but all other functionality cannot be used.

View File

@ -79,15 +79,27 @@ module VagrantPlugins
template_name = 'public_interface' template_name = 'public_interface'
@logger.info("Setting up public interface using device #{@device} in mode #{@mode}") @logger.info("Setting up public interface using device #{@device} in mode #{@mode}")
@ovs = iface_configuration.fetch(:ovs, false) @ovs = iface_configuration.fetch(:ovs, false)
# configuration for tcp tunnel interfaces (p2p conn btwn guest OSes) # configuration for udp or tcp tunnel interfaces (p2p conn btwn guest OSes)
elsif iface_configuration.fetch(:tcp_tunnel_type, nil) elsif iface_configuration.fetch(:tunnel_type, nil)
@tcp_tunnel_port = iface_configuration.fetch(:tcp_tunnel_port, nil) @type = iface_configuration.fetch(:tunnel_type)
raise Errors::TcpTunnelPortNotDefined if @tcp_tunnel_port.nil? @tunnel_port = iface_configuration.fetch(:tunnel_port, nil)
@tcp_tunnel_ip = iface_configuration.fetch(:tcp_tunnel_address, '127.0.0.1') raise Errors::TunnelPortNotDefined if @tunnel_port.nil?
@type = iface_configuration.fetch(:tcp_tunnel_type) if @type == 'udp'
# default udp tunnel source to 127.0.0.1
@udp_tunnel_local_ip = iface_configuration.fetch(:tunnel_local_ip, '127.0.0.1')
@udp_tunnel_local_port = iface_configuration.fetch(:tunnel_local_port)
end
# default mcast tunnel to 239.255.1.1. Web search says this
# 239.255.x.x is a safe range to use for general use mcast
if @type == 'mcast'
default_ip = '239.255.1.1'
else
default_ip = '127.0.0.1'
end
@tunnel_ip = iface_configuration.fetch(:tunnel_address, default_ip)
@model_type = iface_configuration.fetch(:model_type, @nic_model_type) @model_type = iface_configuration.fetch(:model_type, @nic_model_type)
template_name = 'tcp_tunnel_interface' template_name = 'tunnel_interface'
@logger.info("Setting up #{@type} tunnel interface using #{@tcp_tunnel_ip} port #{@tcp_tunnel_port}") @logger.info("Setting up #{@type} tunnel interface using #{@tunnel_ip} port #{@tunnel_port}")
end end
@ -130,7 +142,7 @@ module VagrantPlugins
# Configure interfaces that user requested. Machine should be up and # Configure interfaces that user requested. Machine should be up and
# running now. # running now.
networks_to_configure = [] networks_to_configure = []
adapters.each_with_index do |options, slot_number| adapters.each_with_index do |options, slot_number|
# Skip configuring the management network, which is on the first interface. # Skip configuring the management network, which is on the first interface.
# It's used for provisioning and it has to be available during provisioning, # It's used for provisioning and it has to be available during provisioning,
@ -138,13 +150,13 @@ module VagrantPlugins
next if slot_number == 0 next if slot_number == 0
next if options[:auto_config] === false next if options[:auto_config] === false
@logger.debug "Configuring interface slot_number #{slot_number} options #{options}" @logger.debug "Configuring interface slot_number #{slot_number} options #{options}"
network = { network = {
:interface => slot_number, :interface => slot_number,
:use_dhcp_assigned_default_route => options[:use_dhcp_assigned_default_route], :use_dhcp_assigned_default_route => options[:use_dhcp_assigned_default_route],
:mac_address => options[:mac], :mac_address => options[:mac],
} }
if options[:ip] if options[:ip]
network = { network = {
:type => :static, :type => :static,
@ -154,16 +166,17 @@ module VagrantPlugins
else else
network[:type] = :dhcp network[:type] = :dhcp
end end
# do not run configure_networks for tcp tunnel interfaces # do not run configure_networks for tcp tunnel interfaces
next if options.fetch(:tcp_tunnel_type, nil) next if options.fetch(:tunnel_type, nil)
networks_to_configure << network networks_to_configure << network
end end
env[:ui].info I18n.t('vagrant.actions.vm.network.configuring') env[:ui].info I18n.t('vagrant.actions.vm.network.configuring')
env[:machine].guest.capability( env[:machine].guest.capability(
:configure_networks, networks_to_configure) :configure_networks, networks_to_configure)
end end
end end
@ -179,7 +192,7 @@ module VagrantPlugins
# Return network name according to interface options. # Return network name according to interface options.
def interface_network(libvirt_client, options) def interface_network(libvirt_client, options)
# no need to get interface network for tcp tunnel config # no need to get interface network for tcp tunnel config
return 'tcp_tunnel' if options.fetch(:tcp_tunnel_type, nil) return 'tunnel_interface' if options.fetch(:tunnel_type, nil)
if options[:network_name] if options[:network_name]
@logger.debug "Found network by name" @logger.debug "Found network by name"

View File

@ -36,7 +36,7 @@ module VagrantPlugins
configured_networks(env, @logger).each do |options| configured_networks(env, @logger).each do |options|
# Only need to create private networks # Only need to create private networks
next if options[:iface_type] != :private_network or next if options[:iface_type] != :private_network or
options.fetch(:tcp_tunnel_type, nil) options.fetch(:tunnel_type, nil)
@logger.debug "Searching for network with options #{options}" @logger.debug "Searching for network with options #{options}"
# should fix other methods so this doesn't have to be instance var # should fix other methods so this doesn't have to be instance var
@ -133,7 +133,7 @@ module VagrantPlugins
# Set IP address of network (actually bridge). It will be used as # Set IP address of network (actually bridge). It will be used as
# gateway address for machines connected to this network. # gateway address for machines connected to this network.
net = IPAddr.new(net_address) net = IPAddr.new(net_address)
# Default to first address (after network name) # Default to first address (after network name)
@interface_network[:ip_address] = @options[:host_ip].nil? ? \ @interface_network[:ip_address] = @options[:host_ip].nil? ? \
net.to_range.begin.succ : \ net.to_range.begin.succ : \
@ -158,7 +158,7 @@ module VagrantPlugins
if @interface_network[:created] if @interface_network[:created]
verify_dhcp verify_dhcp
end end
if @options[:network_name] if @options[:network_name]
@logger.debug "Checking that network name does not clash with ip" @logger.debug "Checking that network name does not clash with ip"
if @interface_network[:created] if @interface_network[:created]
@ -177,13 +177,13 @@ module VagrantPlugins
ip_address: @options[:ip], ip_address: @options[:ip],
network_name: @options[:network_name] network_name: @options[:network_name]
end end
# Network with 'name' doesn't exist. Set it as name for new # Network with 'name' doesn't exist. Set it as name for new
# network. # network.
@interface_network[:name] = @options[:network_name] @interface_network[:name] = @options[:network_name]
end end
end end
# Do we need to create new network? # Do we need to create new network?
if !@interface_network[:created] if !@interface_network[:created]
@ -235,7 +235,7 @@ module VagrantPlugins
@interface_network = network if network @interface_network = network if network
# if this interface has a network address, something's wrong. # if this interface has a network address, something's wrong.
if @interface_network[:network_address] if @interface_network[:network_address]
raise Errors::NetworkNotAvailableError, raise Errors::NetworkNotAvailableError,
network_name: @options[:network_name] network_name: @options[:network_name]
end end

View File

@ -106,8 +106,8 @@ module VagrantPlugins
error_key(:activate_network_error) error_key(:activate_network_error)
end end
class TcpTunnelPortNotDefined < VagrantLibvirtError class TunnelPortNotDefined < VagrantLibvirtError
error_key(:tcp_tunnel_port_not_defined) error_key(:tunnel_port_not_defined)
end end
# Other exceptions # Other exceptions

View File

@ -1,7 +0,0 @@
<interface type='<%= @type %>'>
<% if @mac %>
<mac address='<%= @mac %>'/>
<% end %>
<source address='<%=@tcp_tunnel_ip%>' port='<%= @tcp_tunnel_port %>'/>
<model type='<%=@model_type%>'/>
</interface>

View File

@ -0,0 +1,11 @@
<interface type='<%= @type %>'>
<% if @mac %>
<mac address='<%= @mac %>'/>
<% end %>
<source address='<%=@tunnel_ip%>' port='<%= @tunnel_port %>'>
<% if @type == 'udp' %>
<local address='<%=@udp_tunnel_local_ip%>' port='<%=@udp_tunnel_local_port%>' />
<% end %>
</source>
<model type='<%=@model_type%>'/>
</interface>

View File

@ -135,8 +135,8 @@ en:
Error while removing network %{network_name}. %{error_message}. Error while removing network %{network_name}. %{error_message}.
delete_snapshot_error: |- delete_snapshot_error: |-
Error while deleting snapshot: %{error_message}. Error while deleting snapshot: %{error_message}.
tcp_tunnel_port_not_defined: |- tunnel_port_not_defined: |-
TCP tunnel port not defined. tunnel UDP or TCP port not defined.
states: states:
paused: |- paused: |-