From 789fa369c829a2d3b6ceabe261ecc77f333f9fd5 Mon Sep 17 00:00:00 2001 From: stanley karunditu Date: Sat, 11 Jul 2015 10:49:00 -0400 Subject: [PATCH 1/3] add libvirt interface tcp tunnel support. Useful when configuring Virtualized Switch topologies using Switch VMs like Cumulus Linux. vagrant network interface auto_config is disabled in the code. This may be re-enabled in a future update, once it is better understood how to auto configure these types of links. All guestOS ports, for now, that are connected to a tcp tunnel are in a link down state. TCP tunnels allow guest OSes to exchange STP and LLDP information as if they are directly connected to each other. This is not possible with the default virtual switch network mode. Reference: https://libvirt.org/formatdomain.html#elementsNICSTCP --- README.md | 37 ++++++++++++++++++- .../action/create_network_interfaces.rb | 18 ++++++++- lib/vagrant-libvirt/action/create_networks.rb | 3 +- lib/vagrant-libvirt/errors.rb | 4 ++ .../templates/tcp_tunnel_interface.xml.erb | 7 ++++ locales/en.yml | 2 + 6 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 lib/vagrant-libvirt/templates/tcp_tunnel_interface.xml.erb diff --git a/README.md b/README.md index e04d35c..d3f65b6 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,11 @@ Vagrant.configure("2") do |config| ## Networks Networking features in the form of `config.vm.network` support private networks -concept. +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. + +http://wiki.libvirt.org/page/VirtualNetworking +https://libvirt.org/formatdomain.html#elementsNICSTCP 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 @@ -221,14 +225,33 @@ documentation for the details of the macvtap usage. http://www.libvirt.org/formatdomain.html#elementsNICSDirect + An examples of network interface definitions: ```ruby - # Private network + # Private network using virtual network switching config.vm.define :test_vm1 do |test_vm1| test_vm1.vm.network :private_network, :ip => "10.20.30.40" end + # Private network. Point to Point between 2 Guest OS using a TCP tunnel + # Guest 1 + config.vm.define :test_vm1 do |test_vm1| + test_vm1.vm.network :private_network, + :libvirt__tcp_tunnel_type => 'server', + # default is 127.0.0.1 if omitted + # :libvirt__tcp_tunnel_ip => '127.0.0.1', + :libvirt__tcp_tunnel_port => '11111' + + # Guest 2 + config.vm.define :test_vm1 do |test_vm1| + test_vm1.vm.network :private_network, + :libvirt__tcp_tunnel_type => 'client', + # default is 127.0.0.1 if omitted + # :libvirt__tcp_tunnel_ip => '127.0.0.1', + :libvirt__tcp_tunnel_port => '11111' + + # Public Network config.vm.define :test_vm1 do |test_vm1| test_vm1.vm.network :public_network, @@ -290,9 +313,19 @@ starts with 'libvirt__' string. Here is a list of those options: * `:libvirt__forward_device` - Name of interface/device, where network should be forwarded (NATed or routed). Used only when creating new network. By default, all physical interfaces are used. +* `:libvirt_tcp_tunnel_type` - Set it to "server" or "client" to enable TCP + tunnel interface configuration. This configuration type uses TCP tunnels to + 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 + tunnel interfaces and will be ignored if configured. +* `:libvirt_tcp_tunnel_ip` - Sets the source IP of the TCP Tunnel interface. By + default this is `127.0.0.1` +* `:libvirt_tcp_tunnel_port` - Sets the TCP Tunnel interface port that either + the client will connect to, or the server will listen on. * `: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 + When the option `:libvirt__dhcp_enabled` is to to 'false' it shouldn't matter whether the virtual network contains a DHCP server or not and vagrant-libvirt should not fail on it. The only situation where vagrant-libvirt should fail diff --git a/lib/vagrant-libvirt/action/create_network_interfaces.rb b/lib/vagrant-libvirt/action/create_network_interfaces.rb index cbe7562..bd9df2a 100644 --- a/lib/vagrant-libvirt/action/create_network_interfaces.rb +++ b/lib/vagrant-libvirt/action/create_network_interfaces.rb @@ -36,7 +36,6 @@ module VagrantPlugins adapters = [] # Vagrant gives you adapter 0 by default - # Assign interfaces to slots. configured_networks(env, @logger).each do |options| @@ -70,7 +69,6 @@ module VagrantPlugins @mac = iface_configuration.fetch(:mac, false) @model_type = iface_configuration.fetch(:model_type, @nic_model_type) template_name = 'interface' - # Configuration for public interfaces which use the macvtap driver if iface_configuration[:iface_type] == :public_network @device = iface_configuration.fetch(:dev, 'eth0') @@ -80,8 +78,18 @@ module VagrantPlugins template_name = 'public_interface' @logger.info("Setting up public interface using device #{@device} in mode #{@mode}") @ovs = iface_configuration.fetch(:ovs, false) + # configuration for tcp tunnel interfaces (p2p conn btwn guest OSes) + elsif iface_configuration.fetch(:tcp_tunnel_type, nil) + @tcp_tunnel_port = iface_configuration.fetch(:tcp_tunnel_port, nil) + raise Errors::TcpTunnelPortNotDefined if @tcp_tunnel_port.nil? + @tcp_tunnel_ip = iface_configuration.fetch(:tcp_tunnel_address, '127.0.0.1') + @type = iface_configuration.fetch(:tcp_tunnel_type) + @model_type = iface_configuration.fetch(:model_type, @nic_model_type) + template_name = 'tcp_tunnel_interface' + @logger.info("Setting up #{@type} tunnel interface using #{@tcp_tunnel_ip} port #{@tcp_tunnel_port}") end + message = "Creating network interface eth#{@iface_number}" message << " connected to network #{@network_name}." if @mac @@ -144,6 +152,9 @@ module VagrantPlugins network[:type] = :dhcp end + # do not run configure_networks for tcp tunnel interfaces + next if options.fetch(:tcp_tunnel_type, nil) + networks_to_configure << network end @@ -163,6 +174,9 @@ module VagrantPlugins # Return network name according to interface options. def interface_network(libvirt_client, options) + # no need to get interface network for tcp tunnel config + return 'tcp_tunnel' if options.fetch(:tcp_tunnel_type, nil) + if options[:network_name] @logger.debug "Found network by name" return options[:network_name] diff --git a/lib/vagrant-libvirt/action/create_networks.rb b/lib/vagrant-libvirt/action/create_networks.rb index a0d4e54..883c83f 100644 --- a/lib/vagrant-libvirt/action/create_networks.rb +++ b/lib/vagrant-libvirt/action/create_networks.rb @@ -35,7 +35,8 @@ module VagrantPlugins # available, create it if possible. Otherwise raise an error. configured_networks(env, @logger).each do |options| # Only need to create private networks - next if options[:iface_type] != :private_network + next if options[:iface_type] != :private_network or + options.fetch(:tcp_tunnel_type, nil) @logger.debug "Searching for network with options #{options}" # should fix other methods so this doesn't have to be instance var diff --git a/lib/vagrant-libvirt/errors.rb b/lib/vagrant-libvirt/errors.rb index 870c647..863a4f0 100644 --- a/lib/vagrant-libvirt/errors.rb +++ b/lib/vagrant-libvirt/errors.rb @@ -106,6 +106,10 @@ module VagrantPlugins error_key(:activate_network_error) end + class TcpTunnelPortNotDefined < VagrantLibvirtError + error_key(:tcp_tunnel_port_not_defined) + end + # Other exceptions class InterfaceSlotNotAvailable < VagrantLibvirtError error_key(:interface_slot_not_available) diff --git a/lib/vagrant-libvirt/templates/tcp_tunnel_interface.xml.erb b/lib/vagrant-libvirt/templates/tcp_tunnel_interface.xml.erb new file mode 100644 index 0000000..379b740 --- /dev/null +++ b/lib/vagrant-libvirt/templates/tcp_tunnel_interface.xml.erb @@ -0,0 +1,7 @@ + + <% if @mac %> + + <% end %> + + + diff --git a/locales/en.yml b/locales/en.yml index 0644cfc..1ab8e78 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -135,6 +135,8 @@ en: Error while removing network %{network_name}. %{error_message}. delete_snapshot_error: |- Error while deleting snapshot: %{error_message}. + tcp_tunnel_port_not_defined: |- + TCP tunnel port not defined. states: short_paused: |- From 555470efe32015f8f1e2366267e927bbf660a87f Mon Sep 17 00:00:00 2001 From: stanley karunditu Date: Sat, 11 Jul 2015 10:53:23 -0400 Subject: [PATCH 2/3] update README. should say 'test_vm2' instead of 'test_vm1' --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d3f65b6..09b4801 100644 --- a/README.md +++ b/README.md @@ -244,7 +244,7 @@ An examples of network interface definitions: :libvirt__tcp_tunnel_port => '11111' # Guest 2 - config.vm.define :test_vm1 do |test_vm1| + config.vm.define :test_vm2 do |test_vm2| test_vm1.vm.network :private_network, :libvirt__tcp_tunnel_type => 'client', # default is 127.0.0.1 if omitted From a5cd2024ed8288e7bb43e57a0643e42ee0e2a3bc Mon Sep 17 00:00:00 2001 From: stanley karunditu Date: Sat, 11 Jul 2015 10:55:21 -0400 Subject: [PATCH 3/3] update README. fix mention of test_vm1. should be test_vm2 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 09b4801..7a15724 100644 --- a/README.md +++ b/README.md @@ -245,7 +245,7 @@ An examples of network interface definitions: # Guest 2 config.vm.define :test_vm2 do |test_vm2| - test_vm1.vm.network :private_network, + test_vm2.vm.network :private_network, :libvirt__tcp_tunnel_type => 'client', # default is 127.0.0.1 if omitted # :libvirt__tcp_tunnel_ip => '127.0.0.1',