From 5d44f6e758d447e4f10215c218773766a42adf87 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 5 Jan 2015 02:31:03 +0100 Subject: [PATCH 1/2] feature #3208: Implement VXLAN support. Moved common bridge functions from 802.1Q to VLANDriver class. Rename vlan_driver to vlan_tag_driver for 802.1Q. --- install.sh | 11 +- src/vnm_mad/remotes/802.1Q/pre | 4 +- .../{vlan_driver.rb => vlan_tag_driver.rb} | 85 +++----------- src/vnm_mad/remotes/OpenNebulaNetwork.conf | 7 ++ src/vnm_mad/remotes/lib/vlan.rb | 110 ++++++++++++++++++ src/vnm_mad/remotes/lib/vnm_driver.rb | 26 +---- src/vnm_mad/remotes/lib/vnmmad.rb | 2 +- src/vnm_mad/remotes/vxlan/clean | 1 + src/vnm_mad/remotes/vxlan/post | 1 + src/vnm_mad/remotes/vxlan/pre | 25 ++++ src/vnm_mad/remotes/vxlan/vxlan_driver.rb | 81 +++++++++++++ 11 files changed, 256 insertions(+), 97 deletions(-) rename src/vnm_mad/remotes/802.1Q/{vlan_driver.rb => vlan_tag_driver.rb} (56%) create mode 100644 src/vnm_mad/remotes/lib/vlan.rb create mode 120000 src/vnm_mad/remotes/vxlan/clean create mode 120000 src/vnm_mad/remotes/vxlan/post create mode 100755 src/vnm_mad/remotes/vxlan/pre create mode 100644 src/vnm_mad/remotes/vxlan/vxlan_driver.rb diff --git a/install.sh b/install.sh index 6c9907c2fd..0f9a450e15 100755 --- a/install.sh +++ b/install.sh @@ -262,6 +262,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/vmm/az \ $VAR_LOCATION/remotes/vnm \ $VAR_LOCATION/remotes/vnm/802.1Q \ + $VAR_LOCATION/remotes/vnm/vxlan \ $VAR_LOCATION/remotes/vnm/dummy \ $VAR_LOCATION/remotes/vnm/ebtables \ $VAR_LOCATION/remotes/vnm/fw \ @@ -449,6 +450,7 @@ INSTALL_FILES=( DATASTORE_DRIVER_DEV_SCRIPTS:$VAR_LOCATION/remotes/datastore/dev NETWORK_FILES:$VAR_LOCATION/remotes/vnm NETWORK_8021Q_FILES:$VAR_LOCATION/remotes/vnm/802.1Q + NETWORK_VXLAN_FILES:$VAR_LOCATION/remotes/vnm/vxlan NETWORK_DUMMY_FILES:$VAR_LOCATION/remotes/vnm/dummy NETWORK_EBTABLES_FILES:$VAR_LOCATION/remotes/vnm/ebtables NETWORK_FW_FILES:$VAR_LOCATION/remotes/vnm/fw @@ -940,6 +942,7 @@ NETWORK_FILES="src/vnm_mad/remotes/lib/vnm_driver.rb \ src/vnm_mad/remotes/lib/address.rb \ src/vnm_mad/remotes/lib/command.rb \ src/vnm_mad/remotes/lib/vm.rb \ + src/vnm_mad/remotes/lib/vlan.rb \ src/vnm_mad/remotes/lib/security_groups.rb \ src/vnm_mad/remotes/lib/security_groups_iptables.rb \ src/vnm_mad/remotes/lib/nic.rb" @@ -947,7 +950,13 @@ NETWORK_FILES="src/vnm_mad/remotes/lib/vnm_driver.rb \ NETWORK_8021Q_FILES="src/vnm_mad/remotes/802.1Q/clean \ src/vnm_mad/remotes/802.1Q/post \ src/vnm_mad/remotes/802.1Q/pre \ - src/vnm_mad/remotes/802.1Q/vlan_driver.rb" + src/vnm_mad/remotes/802.1Q/vlan_tag_driver.rb" + +NETWORK_VXLAN_FILES="src/vnm_mad/remotes/vxlan/clean \ + src/vnm_mad/remotes/vxlan/post \ + src/vnm_mad/remotes/vxlan/pre \ + src/vnm_mad/remotes/vxlan/vxlan_driver.rb" + NETWORK_DUMMY_FILES="src/vnm_mad/remotes/dummy/clean \ src/vnm_mad/remotes/dummy/post \ diff --git a/src/vnm_mad/remotes/802.1Q/pre b/src/vnm_mad/remotes/802.1Q/pre index 656fca6415..1dd5d1d12d 100755 --- a/src/vnm_mad/remotes/802.1Q/pre +++ b/src/vnm_mad/remotes/802.1Q/pre @@ -19,7 +19,7 @@ $: << File.dirname(__FILE__) $: << File.join(File.dirname(__FILE__), "..") -require 'vlan_driver' +require 'vlan_tag_driver' -hm = VLANDriver.from_base64(ARGV[0]) +hm = VLANTagDriver.from_base64(ARGV[0]) exit hm.activate diff --git a/src/vnm_mad/remotes/802.1Q/vlan_driver.rb b/src/vnm_mad/remotes/802.1Q/vlan_tag_driver.rb similarity index 56% rename from src/vnm_mad/remotes/802.1Q/vlan_driver.rb rename to src/vnm_mad/remotes/802.1Q/vlan_tag_driver.rb index f3dcf5dabc..a06bee77c0 100644 --- a/src/vnm_mad/remotes/802.1Q/vlan_driver.rb +++ b/src/vnm_mad/remotes/802.1Q/vlan_tag_driver.rb @@ -23,7 +23,7 @@ require 'vnmmad' # # Once activated the VM will be attached to this bridge ################################################################################ -class VLANDriver < VNMMAD::VNMDriver +class VLANTagDriver < VNMMAD::VLANDriver # DRIVER name and XPATH for relevant NICs DRIVER = "802.1Q" @@ -33,12 +33,9 @@ class VLANDriver < VNMMAD::VNMDriver # Creatges the driver device operations are not locked ############################################################################ def initialize(vm, deploy_id = nil, hypervisor = nil) - super(vm, XPATH_FILTER, deploy_id, hypervisor) @locking = false - lock - @bridges = get_interfaces - unlock + super(vm, XPATH_FILTER, deploy_id, hypervisor) end ############################################################################ @@ -47,33 +44,21 @@ class VLANDriver < VNMMAD::VNMDriver def activate lock - vm_id = @vm['ID'] + vm_id = @vm['ID'] + options = Hash.new process do |nic| - bridge = nic[:bridge] - dev = nic[:phydev] - if dev - if nic[:vlan_id] - vlan = nic[:vlan_id] - else - vlan = CONF[:start_vlan] + nic[:network_id].to_i - end + options.clear - if !bridge_exists? bridge - create_bridge bridge - ifup bridge - end + options[:bridge] = nic[:bridge] + options[:phydev] = nic[:phydev] + options[:vlan_id] = nic[:vlan_id] + options[:network_id] = nic[:network_id] - if !device_exists?(dev, vlan) - create_dev_vlan(dev, vlan) - ifup(dev, vlan) - end + return if options[:phydev].nil? - if !attached_bridge_dev?(bridge, dev, vlan) - attach_brigde_dev(bridge, dev, vlan) - end - end + set_up_vlan(options) end unlock @@ -82,49 +67,13 @@ class VLANDriver < VNMMAD::VNMDriver end ############################################################################ - # Private interface, methods to manage bridges and VLAN tags through the - # brctl and ip commands + # This function creates and activate a VLAN device ############################################################################ - private + def create_vlan_dev(options) + OpenNebula.exec_and_log("#{command(:ip)} link add link"\ + " #{options[:phydev]} name #{options[:vlan_dev]} type vlan id"\ + " #{options[:vlan_id]}") - def bridge_exists?(bridge) - @bridges.keys.include? bridge - end - - def create_bridge(bridge) - OpenNebula.exec_and_log("#{command(:brctl)} addbr #{bridge}") - @bridges[bridge] = Array.new - end - - def device_exists?(dev, vlan=nil) - dev = "#{dev}.#{vlan}" if vlan - `#{command(:ip)} link show #{dev}` - $?.exitstatus == 0 - end - - def create_dev_vlan(dev, vlan) - cmd = "#{command(:ip)} link add link #{dev}" - cmd << " name #{dev}.#{vlan} type vlan id #{vlan}" - - OpenNebula.exec_and_log(cmd) - end - - def attached_bridge_dev?(bridge, dev, vlan=nil) - return false if !bridge_exists? bridge - - dev = "#{dev}.#{vlan}" if vlan - @bridges[bridge].include? dev - end - - def attach_brigde_dev(bridge, dev, vlan=nil) - dev = "#{dev}.#{vlan}" if vlan - - OpenNebula.exec_and_log("#{command(:brctl)} addif #{bridge} #{dev}") - @bridges[bridge] << dev - end - - def ifup(dev, vlan=nil) - dev = "#{dev}.#{vlan}" if vlan - OpenNebula.exec_and_log("#{command(:ip)} link set #{dev} up") + OpenNebula.exec_and_log("#{command(:ip)} link set #{options[:vlan_dev]} up") end end diff --git a/src/vnm_mad/remotes/OpenNebulaNetwork.conf b/src/vnm_mad/remotes/OpenNebulaNetwork.conf index 8ab0d99ad4..f622b63d87 100644 --- a/src/vnm_mad/remotes/OpenNebulaNetwork.conf +++ b/src/vnm_mad/remotes/OpenNebulaNetwork.conf @@ -27,3 +27,10 @@ # Enable ARP Cache Poisoning Prevention Rules :arp_cache_poisoning: true + +################################################################################ +# VXLAN Options +################################################################################ + +# Base multicast address for each VLAN. The mc address is :vxlan_mc + :vlan_id +:vxlan_mc: 239.0.0.0 diff --git a/src/vnm_mad/remotes/lib/vlan.rb b/src/vnm_mad/remotes/lib/vlan.rb new file mode 100644 index 0000000000..0336f72b9c --- /dev/null +++ b/src/vnm_mad/remotes/lib/vlan.rb @@ -0,0 +1,110 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +module VNMMAD + + ############################################################################ + # Module to use as mixin for implementing VLAN drivers based on special + # link devices though the Linux kernel features and bridges. It provides + # common functionality to handle bridges + ############################################################################ + class VLANDriver < VNMMAD::VNMDriver + + def initialize(vm_tpl, xpath_filter, deploy_id = nil, hypervisor = nil) + super(vm_tpl, xpath_filter, deploy_id, hypervisor) + + lock + @bridges = get_bridges + unlock + end + + # This function needs to be implemented by any VLAN driver to + # create the VLAN device. The device MUST be set up by this function + # Options is a driver specific hash. It includes + # :vlan_dev the name for the VLAN device + # :phydev Physical Device to bind the VLAN traffic to + # :vlan_id the VLAN ID + # : additional driver specific parameters + def create_vlan_dev(options) + OpenNebula.log_error("create_vlan_dev function not implemented.") + + exit -1 + end + + # Set ups the VLAN for the VMs. + # @param options [Hash] including + # - :phydev Physical Device to bind the VLAN traffic to + # - :bridge Name of the bridge to attach the VMs and VLAN dev to + # - :network_id + def set_up_vlan(options) + + if options[:vlan_id].nil? + options[:vlan_id] = CONF[:start_vlan] + options[:network_id].to_i + end + + options[:vlan_dev] = "#{options[:phydev]}.#{options[:vlan_id]}" + + create_bridge(options[:bridge]) + + return if @bridges[options[:bridge]].include? options[:vlan_dev] + + create_vlan_dev(options) + + OpenNebula.exec_and_log("#{command(:brctl)} addif"\ + " #{options[:bridge]} #{options[:vlan_dev]}") + + @bridges[options[:bridge]] << options[:vlan_dev] + end + + private + # Creates a bridge if it does not exists, and brings it up. + # This function IS FINAL, exits if action cannot be completed + # @param bridge [String] the bridge name + def create_bridge(bridge) + return if @bridges.keys.include? bridge + + OpenNebula.exec_and_log("#{command(:brctl)} addbr #{bridge}") + + @bridges[bridge] = Array.new + + OpenNebula.exec_and_log("#{command(:ip)} link set #{bridge} up") + end + + # Get hypervisor bridges + # @return [Hash] with the bridge names + def get_bridges + bridges = Hash.new + brctl_exit =`#{VNMNetwork::COMMANDS[:brctl]} show` + + cur_bridge = "" + + brctl_exit.split("\n")[1..-1].each do |l| + l = l.split + + if l.length > 1 + cur_bridge = l[0] + + bridges[cur_bridge] = Array.new + bridges[cur_bridge] << l[3] if l[3] + else + bridges[cur_bridge] << l[0] + end + end + + bridges + end + end +end diff --git a/src/vnm_mad/remotes/lib/vnm_driver.rb b/src/vnm_mad/remotes/lib/vnm_driver.rb index f62df56e06..8ee3ba71c9 100644 --- a/src/vnm_mad/remotes/lib/vnm_driver.rb +++ b/src/vnm_mad/remotes/lib/vnm_driver.rb @@ -35,7 +35,7 @@ module VNMMAD # @param deploy_id [String] # @param hypervisor [String] def initialize(vm_tpl, xpath_filter, deploy_id = nil, hypervisor = nil) - @locking = false + @locking ||= false if !hypervisor @hypervisor = detect_hypervisor @@ -92,30 +92,6 @@ module VNMMAD nil end end - - # Get hypervisor bridges - # @return [Hash] with the bridge names - def get_interfaces - bridges = Hash.new - brctl_exit =`#{VNMNetwork::COMMANDS[:brctl]} show` - - cur_bridge = "" - - brctl_exit.split("\n")[1..-1].each do |l| - l = l.split - - if l.length > 1 - cur_bridge = l[0] - - bridges[cur_bridge] = Array.new - bridges[cur_bridge] << l[3] if l[3] - else - bridges[cur_bridge] << l[0] - end - end - - bridges - end # Returns true if the template contains the deprecated firewall attributes: # - ICMP diff --git a/src/vnm_mad/remotes/lib/vnmmad.rb b/src/vnm_mad/remotes/lib/vnmmad.rb index dad4386931..08c816acdf 100644 --- a/src/vnm_mad/remotes/lib/vnmmad.rb +++ b/src/vnm_mad/remotes/lib/vnmmad.rb @@ -30,7 +30,7 @@ require 'security_groups_iptables' require 'vnm_driver' require 'fw_driver' require 'sg_driver' - +require 'vlan' require 'scripts_common' include OpenNebula diff --git a/src/vnm_mad/remotes/vxlan/clean b/src/vnm_mad/remotes/vxlan/clean new file mode 120000 index 0000000000..940540d063 --- /dev/null +++ b/src/vnm_mad/remotes/vxlan/clean @@ -0,0 +1 @@ +../fw/clean \ No newline at end of file diff --git a/src/vnm_mad/remotes/vxlan/post b/src/vnm_mad/remotes/vxlan/post new file mode 120000 index 0000000000..e0046b5997 --- /dev/null +++ b/src/vnm_mad/remotes/vxlan/post @@ -0,0 +1 @@ +../fw/post \ No newline at end of file diff --git a/src/vnm_mad/remotes/vxlan/pre b/src/vnm_mad/remotes/vxlan/pre new file mode 100755 index 0000000000..a44a58d8a8 --- /dev/null +++ b/src/vnm_mad/remotes/vxlan/pre @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +$: << File.dirname(__FILE__) +$: << File.join(File.dirname(__FILE__), "..") + +require 'vxlan_driver' + +hm = VXLANDriver.from_base64(ARGV[0]) +exit hm.activate diff --git a/src/vnm_mad/remotes/vxlan/vxlan_driver.rb b/src/vnm_mad/remotes/vxlan/vxlan_driver.rb new file mode 100644 index 0000000000..7dda6b0bf3 --- /dev/null +++ b/src/vnm_mad/remotes/vxlan/vxlan_driver.rb @@ -0,0 +1,81 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +require 'vnmmad' + +################################################################################ +# This driver tag VM traffic with a VLAN_ID using VXLAN protocol. Features: +# - Creates a bridge and bind phisycal device if not present +# - Creates a tagged interface for the VM dev.vlan_id +# +# Once activated the VM will be attached to this bridge +################################################################################ +class VXLANDriver < VNMMAD::VLANDriver + + # DRIVER name and XPATH for relevant NICs + DRIVER = "vxlan" + XPATH_FILTER = "TEMPLATE/NIC[VLAN='YES']" + + ############################################################################ + # Creatges the driver device operations are not locked + ############################################################################ + def initialize(vm, deploy_id = nil, hypervisor = nil) + @locking = false + + super(vm, XPATH_FILTER, deploy_id, hypervisor) + end + + ############################################################################ + # Activate the driver and creates bridges and tags devices as needed. + ############################################################################ + def activate + lock + + options = Hash.new + + process do |nic| + + options.clear + + options[:bridge] = nic[:bridge] + options[:phydev] = nic[:phydev] + options[:vlan_id] = nic[:vlan_id] + options[:network_id] = nic[:network_id] + + return if options[:phydev].nil? + + set_up_vlan(options) + end + + unlock + + return 0 + end + + ############################################################################ + # This function creates and activate a VLAN device + ############################################################################ + def create_vlan_dev(options) + mc = VNMMAD::VNMNetwork::IPv4.to_i(CONF[:vxlan_mc]) + options[:vlan_id].to_i + mcs = VNMMAD::VNMNetwork::IPv4.to_s(mc) + + OpenNebula.exec_and_log("#{command(:ip)} link add #{options[:vlan_dev]}"\ + " type vxlan id #{options[:vlan_id]} group #{mcs}"\ + " dev #{options[:phydev]}") + + OpenNebula.exec_and_log("#{command(:ip)} link set #{options[:vlan_dev]} up") + end +end From 5759fb384316109354e8bfe9dfbe4e3635e30ac4 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Mon, 5 Jan 2015 16:37:43 +0100 Subject: [PATCH 2/2] feature #3208: Move common activate function to VLANDriver base class --- src/vnm_mad/remotes/802.1Q/vlan_tag_driver.rb | 28 ----------- src/vnm_mad/remotes/lib/vlan.rb | 47 ++++++++++++++----- src/vnm_mad/remotes/vxlan/vxlan_driver.rb | 27 ----------- 3 files changed, 36 insertions(+), 66 deletions(-) diff --git a/src/vnm_mad/remotes/802.1Q/vlan_tag_driver.rb b/src/vnm_mad/remotes/802.1Q/vlan_tag_driver.rb index a06bee77c0..bc2f6c0ce1 100644 --- a/src/vnm_mad/remotes/802.1Q/vlan_tag_driver.rb +++ b/src/vnm_mad/remotes/802.1Q/vlan_tag_driver.rb @@ -38,34 +38,6 @@ class VLANTagDriver < VNMMAD::VLANDriver super(vm, XPATH_FILTER, deploy_id, hypervisor) end - ############################################################################ - # Activate the driver and creates bridges and tags devices as needed. - ############################################################################ - def activate - lock - - vm_id = @vm['ID'] - options = Hash.new - - process do |nic| - - options.clear - - options[:bridge] = nic[:bridge] - options[:phydev] = nic[:phydev] - options[:vlan_id] = nic[:vlan_id] - options[:network_id] = nic[:network_id] - - return if options[:phydev].nil? - - set_up_vlan(options) - end - - unlock - - return 0 - end - ############################################################################ # This function creates and activate a VLAN device ############################################################################ diff --git a/src/vnm_mad/remotes/lib/vlan.rb b/src/vnm_mad/remotes/lib/vlan.rb index 0336f72b9c..0a2f20e951 100644 --- a/src/vnm_mad/remotes/lib/vlan.rb +++ b/src/vnm_mad/remotes/lib/vlan.rb @@ -31,17 +31,29 @@ module VNMMAD unlock end - # This function needs to be implemented by any VLAN driver to - # create the VLAN device. The device MUST be set up by this function - # Options is a driver specific hash. It includes - # :vlan_dev the name for the VLAN device - # :phydev Physical Device to bind the VLAN traffic to - # :vlan_id the VLAN ID - # : additional driver specific parameters - def create_vlan_dev(options) - OpenNebula.log_error("create_vlan_dev function not implemented.") + # Activate the driver and creates bridges and tags devices as needed. + def activate + lock - exit -1 + options = Hash.new + + process do |nic| + + options.clear + + options[:bridge] = nic[:bridge] + options[:phydev] = nic[:phydev] + options[:vlan_id] = nic[:vlan_id] + options[:network_id] = nic[:network_id] + + return if options[:phydev].nil? + + set_up_vlan(options) + end + + unlock + + return 0 end # Set ups the VLAN for the VMs. @@ -68,7 +80,20 @@ module VNMMAD @bridges[options[:bridge]] << options[:vlan_dev] end - + + # This function needs to be implemented by any VLAN driver to + # create the VLAN device. The device MUST be set up by this function + # Options is a driver specific hash. It includes + # :vlan_dev the name for the VLAN device + # :phydev Physical Device to bind the VLAN traffic to + # :vlan_id the VLAN ID + # : additional driver specific parameters + def create_vlan_dev(options) + OpenNebula.log_error("create_vlan_dev function not implemented.") + + exit -1 + end + private # Creates a bridge if it does not exists, and brings it up. # This function IS FINAL, exits if action cannot be completed diff --git a/src/vnm_mad/remotes/vxlan/vxlan_driver.rb b/src/vnm_mad/remotes/vxlan/vxlan_driver.rb index 7dda6b0bf3..c145db4726 100644 --- a/src/vnm_mad/remotes/vxlan/vxlan_driver.rb +++ b/src/vnm_mad/remotes/vxlan/vxlan_driver.rb @@ -38,33 +38,6 @@ class VXLANDriver < VNMMAD::VLANDriver super(vm, XPATH_FILTER, deploy_id, hypervisor) end - ############################################################################ - # Activate the driver and creates bridges and tags devices as needed. - ############################################################################ - def activate - lock - - options = Hash.new - - process do |nic| - - options.clear - - options[:bridge] = nic[:bridge] - options[:phydev] = nic[:phydev] - options[:vlan_id] = nic[:vlan_id] - options[:network_id] = nic[:network_id] - - return if options[:phydev].nil? - - set_up_vlan(options) - end - - unlock - - return 0 - end - ############################################################################ # This function creates and activate a VLAN device ############################################################################