diff --git a/lib/puppet/parser/functions/validate_network_vlan_ranges.rb b/lib/puppet/parser/functions/validate_network_vlan_ranges.rb new file mode 100644 index 000000000..013ee085d --- /dev/null +++ b/lib/puppet/parser/functions/validate_network_vlan_ranges.rb @@ -0,0 +1,44 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# Martin Magr +# +# 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. +# +# Advanced validation for VLAN configuration +# + +module Puppet::Parser::Functions + newfunction(:validate_network_vlan_ranges) do |args| + value = args[0] + if not value.kind_of?(Array) + value = [value] + end + + value.each do |range| + if m = /^(.+:)?(\d+):(\d+)$/.match(range) + first_id = Integer(m[-2]) + second_id = Integer(m[-1]) + if (first_id > 4094) || (second_id > 4094) + raise Puppet::Error, "vlan id are invalid." + end + if ((second_id - first_id) < 0 ) + raise Puppet::Error, "network vlan ranges are invalid." + end + elsif range + raise Puppet::Error, "network vlan ranges are invalid." + end + end + end +end diff --git a/lib/puppet/parser/functions/validate_tunnel_id_ranges.rb b/lib/puppet/parser/functions/validate_tunnel_id_ranges.rb new file mode 100644 index 000000000..d13d5530f --- /dev/null +++ b/lib/puppet/parser/functions/validate_tunnel_id_ranges.rb @@ -0,0 +1,44 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# Martin Magr +# +# 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. +# +# Advanced validation when using GRE +# + +module Puppet::Parser::Functions + newfunction(:validate_tunnel_id_ranges) do |args| + value = args[0] + if not value.kind_of?(Array) + value = [value] + end + + value.each do |range| + if m = /^(\d+):(\d+)$/.match(range) + first_id = Integer(m[1]) + second_id = Integer(m[2]) + if ((second_id - first_id) > 1000000) + raise Puppet::Error, "tunnel id ranges are to large." + end + if ((second_id - first_id) < 0 ) + raise Puppet::Error, "tunnel id ranges are invalid." + end + elsif range + raise Puppet::Error, "tunnel id ranges are invalid." + end + end + end +end diff --git a/lib/puppet/parser/functions/validate_vni_ranges.rb b/lib/puppet/parser/functions/validate_vni_ranges.rb new file mode 100644 index 000000000..d222bdb85 --- /dev/null +++ b/lib/puppet/parser/functions/validate_vni_ranges.rb @@ -0,0 +1,47 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# Martin Magr +# +# 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. +# +# Advanced validation when using VXLAN +# + +module Puppet::Parser::Functions + newfunction(:validate_vni_ranges) do |args| + value = args[0] + if not value.kind_of?(Array) + value = [value] + end + + value.each do |range| + if m = /^(\d+):(\d+)$/.match(range) + first_id = Integer(m[1]) + second_id = Integer(m[2]) + if not (0 <= first_id && first_id <= 16777215) + raise Puppet::Error, "vni ranges are invalid." + end + if not (0 <= second_id && second_id <= 16777215) + raise Puppet::Error, "vni ranges are invalid." + end + if (second_id < first_id) + raise Puppet::Error, "vni ranges are invalid." + end + elsif range + raise Puppet::Error, "vni ranges are invalid." + end + end + end +end diff --git a/manifests/plugins/ml2/validate_network_vlan_ranges.pp b/lib/puppet/parser/functions/validate_vxlan_udp_port.rb similarity index 58% rename from manifests/plugins/ml2/validate_network_vlan_ranges.pp rename to lib/puppet/parser/functions/validate_vxlan_udp_port.rb index 1e86d14aa..25b711032 100644 --- a/manifests/plugins/ml2/validate_network_vlan_ranges.pp +++ b/lib/puppet/parser/functions/validate_vxlan_udp_port.rb @@ -2,6 +2,7 @@ # Copyright (C) 2013 eNovance SAS # # Author: Emilien Macchi +# Martin Magr # # 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 @@ -15,16 +16,17 @@ # License for the specific language governing permissions and limitations # under the License. # -# Advanced testing for VLAN configuration +# Advanced validation for VXLAN UDP port configuration # -define neutron::plugins::ml2::validate_network_vlan_ranges { - $first_id = regsubst($name,'^(\d+):(\d+)$','\1') + 0 - $second_id = regsubst($name,'^(\d+):(\d+)$','\2') + 0 - if ($first_id > 4094) or ($second_id > 4094) { - fail('vlan id are invalid.') - } - if (($second_id - $first_id) < 0 ) { - fail('network vlan ranges are invalid.') - } -} +module Puppet::Parser::Functions + newfunction(:validate_vxlan_udp_port) do |args| + value = Integer(args[0]) + + # check if port is either default value or one of the private ports + # according to http://tools.ietf.org/html/rfc6056 + if value != 4789 or (49151 >= value and value > 65535) + raise Puppet::Error, "vxlan udp port is invalid." + end + end +end diff --git a/manifests/agents/ovs.pp b/manifests/agents/ovs.pp index 248db8706..2d952b121 100644 --- a/manifests/agents/ovs.pp +++ b/manifests/agents/ovs.pp @@ -15,8 +15,10 @@ class neutron::agents::ovs ( $bridge_mappings = [], $integration_bridge = 'br-int', $enable_tunneling = false, + $tunnel_types = [], $local_ip = false, $tunnel_bridge = 'br-tun', + $vxlan_udp_port = 4789, $polling_interval = 2, $firewall_driver = 'neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver' ) { @@ -86,6 +88,18 @@ class neutron::agents::ovs ( 'OVS/tunnel_bridge': value => $tunnel_bridge; 'OVS/local_ip': value => $local_ip; } + + if $tunnel_types { + neutron_plugin_ovs { + 'agent/tunnel_types': value => join($tunnel_types, ','); + } + } + if 'vxlan' in $tunnel_types { + validate_vxlan_udp_port($vxlan_udp_port) + neutron_plugin_ovs { + 'agent/vxlan_udp_port': value => $vxlan_udp_port; + } + } } else { neutron_plugin_ovs { 'OVS/enable_tunneling': value => false; diff --git a/manifests/plugins/ml2.pp b/manifests/plugins/ml2.pp index 426bfd46f..ee74e8799 100644 --- a/manifests/plugins/ml2.pp +++ b/manifests/plugins/ml2.pp @@ -89,7 +89,7 @@ class neutron::plugins::ml2 ( $tenant_network_types = ['local', 'flat', 'vlan', 'gre', 'vxlan'], $mechanism_drivers = ['openvswitch', 'linuxbridge'], $flat_networks = ['*'], - $network_vlan_ranges = ['10:50'], + $network_vlan_ranges = ['physnet1:1000:2999'], $tunnel_id_ranges = ['20:100'], $vxlan_group = '224.0.0.1', $vni_ranges = ['10:100'] diff --git a/manifests/plugins/ml2/driver.pp b/manifests/plugins/ml2/driver.pp index 65532591d..f9eddc23a 100644 --- a/manifests/plugins/ml2/driver.pp +++ b/manifests/plugins/ml2/driver.pp @@ -36,7 +36,7 @@ define neutron::plugins::ml2::driver ( fail('when gre is part of type_drivers, tunnel_id_ranges should be given.') } - neutron::plugins::ml2::validate_tunnel_id_ranges { $tunnel_id_ranges:; } + validate_tunnel_id_ranges($tunnel_id_ranges) neutron_plugin_ml2 { 'ml2_type_gre/tunnel_id_ranges': value => join($tunnel_id_ranges, ','); @@ -48,7 +48,7 @@ define neutron::plugins::ml2::driver ( fail('when vlan is part of type_drivers, network_vlan_ranges should be given.') } - neutron::plugins::ml2::validate_network_vlan_ranges { $network_vlan_ranges:; } + validate_network_vlan_ranges($network_vlan_ranges) neutron_plugin_ml2 { 'ml2_type_vlan/network_vlan_ranges': value => join($network_vlan_ranges, ','); @@ -73,7 +73,7 @@ define neutron::plugins::ml2::driver ( } } - neutron::plugins::ml2::validate_vni_ranges { $vni_ranges: } + validate_vni_ranges($vni_ranges) neutron_plugin_ml2 { 'ml2_type_vxlan/vxlan_group': value => $vxlan_group; diff --git a/manifests/plugins/ml2/validate_tunnel_id_ranges.pp b/manifests/plugins/ml2/validate_tunnel_id_ranges.pp deleted file mode 100644 index e55e46c6f..000000000 --- a/manifests/plugins/ml2/validate_tunnel_id_ranges.pp +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (C) 2013 eNovance SAS -# -# Author: Emilien Macchi -# -# 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. -# -# Advanced testing when using GRE -# - -define neutron::plugins::ml2::validate_tunnel_id_ranges { - $first_id = regsubst($name,'^(\d+):(\d+)$','\1') + 0 - $second_id = regsubst($name,'^(\d+):(\d+)$','\2') + 0 - if (($second_id - $first_id) > 1000000) { - fail('tunnel id ranges are to large.') - } - if (($second_id - $first_id) < 0 ) { - fail('tunnel id ranges are invalid.') - } -} diff --git a/manifests/plugins/ml2/validate_vni_ranges.pp b/manifests/plugins/ml2/validate_vni_ranges.pp deleted file mode 100644 index 125e25bb0..000000000 --- a/manifests/plugins/ml2/validate_vni_ranges.pp +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (C) 2013 eNovance SAS -# -# Author: Emilien Macchi -# -# 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. -# -# Advanced testing when using VXLAN -# - -define neutron::plugins::ml2::validate_vni_ranges { - if ($name !~ /^(\d+):(\d+)$/) { - fail('vni ranges are invalid.') - } - else { - $first_id = regsubst($name,'^(\d+):(\d+)$','\1') + 0 - $second_id = regsubst($name,'^(\d+):(\d+)$','\2') + 0 - if ( $first_id > 16777215 ) or ( $second_id > 16777215 ) - or ( $first_id < 0 ) or ( $second_id < 0 ) - or ( $second_id < $first_id ) { - fail('vni ranges are invalid.') - } - } -} diff --git a/manifests/plugins/ovs.pp b/manifests/plugins/ovs.pp index f01ca3af7..349e316b9 100644 --- a/manifests/plugins/ovs.pp +++ b/manifests/plugins/ovs.pp @@ -19,7 +19,8 @@ class neutron::plugins::ovs ( # if type is vlan or flat, a default of physnet1:1000:2000 is used # otherwise this will not be set by default. $network_vlan_ranges = undef, - $tunnel_id_ranges = '1:1000' + $tunnel_id_ranges = '1:1000', + $vxlan_udp_port = 4789 ) { include neutron::params @@ -56,31 +57,33 @@ class neutron::plugins::ovs ( 'OVS/tenant_network_type': value => $tenant_network_type; } - if($tenant_network_type == 'gre') { + if $tenant_network_type in ['gre', 'vxlan'] { + validate_tunnel_id_ranges($tunnel_id_ranges) neutron_plugin_ovs { # this is set by the plugin and the agent - since the plugin node has the agent installed # we rely on it setting it. # TODO(ijw): do something with a virtualised node # 'OVS/enable_tunneling': value => 'True'; 'OVS/tunnel_id_ranges': value => $tunnel_id_ranges; + 'OVS/tunnel_type': value => $tenant_network_type; } } - # If the user hasn't specified vlan_ranges, fail for the modes where - # it is required, otherwise keep it absent - if ($tenant_network_type == 'vlan') or ($tenant_network_type == 'flat') { - if ! $network_vlan_ranges { + validate_vxlan_udp_port($vxlan_udp_port) + neutron_plugin_ovs { 'OVS/vxlan_udp_port': value => $vxlan_udp_port; } + + if ! $network_vlan_ranges { + # If the user hasn't specified vlan_ranges, fail for the modes where + # it is required, otherwise keep it absent + if $tenant_network_type in ['vlan', 'flat'] { fail('When using the vlan network type, network_vlan_ranges is required') - } - } else { - if ! $network_vlan_ranges { + } else { neutron_plugin_ovs { 'OVS/network_vlan_ranges': ensure => absent } } - } - - # This might be set by the user for the gre case where - # provider networks are in use - if $network_vlan_ranges { + } else { + # This might be set by the user for the gre or vxlan case where + # provider networks are in use + validate_network_vlan_ranges($network_vlan_ranges) neutron_plugin_ovs { 'OVS/network_vlan_ranges': value => $network_vlan_ranges } diff --git a/spec/classes/neutron_agents_ovs_spec.rb b/spec/classes/neutron_agents_ovs_spec.rb index e9cd8d00e..b686c5e39 100644 --- a/spec/classes/neutron_agents_ovs_spec.rb +++ b/spec/classes/neutron_agents_ovs_spec.rb @@ -4,7 +4,7 @@ describe 'neutron::agents::ovs' do let :pre_condition do "class { 'neutron': rabbit_password => 'passw0rd' }\n" + - "class { 'neutron::plugins::ovs': network_vlan_ranges => 'test' }" + "class { 'neutron::plugins::ovs': network_vlan_ranges => 'physnet1:1000:2000' }" end let :default_params do @@ -126,6 +126,20 @@ describe 'neutron::agents::ovs' do ) end end + + context 'with vxlan tunneling' do + before :each do + params.merge!(:enable_tunneling => true, + :local_ip => '127.0.0.1', + :tunnel_types => ['vxlan'], + :vxlan_udp_port => '4789') + end + + it 'should perform vxlan network configuration' do + should contain_neutron_plugin_ovs('agent/tunnel_types').with_value(params[:tunnel_types]) + should contain_neutron_plugin_ovs('agent/vxlan_udp_port').with_value(params[:vxlan_udp_port]) + end + end end end diff --git a/spec/classes/neutron_plugins_ovs_spec.rb b/spec/classes/neutron_plugins_ovs_spec.rb index a54112a31..36efd040d 100644 --- a/spec/classes/neutron_plugins_ovs_spec.rb +++ b/spec/classes/neutron_plugins_ovs_spec.rb @@ -24,7 +24,7 @@ describe 'neutron::plugins::ovs' do shared_examples_for 'neutron ovs plugin' do before do - params.merge!(default_params) + params.merge!(default_params) { |key, v1, v2| v1 } end let :params do @@ -57,12 +57,13 @@ describe 'neutron::plugins::ovs' do end before do - params.delete('network_vlan_ranges') + params.delete(:network_vlan_ranges) end it 'should perform gre network configuration' do should contain_neutron_plugin_ovs('OVS/tenant_network_type').with_value(params[:tenant_network_type]) should contain_neutron_plugin_ovs('OVS/tunnel_id_ranges').with_value(params[:tunnel_id_ranges]) + should contain_neutron_plugin_ovs('OVS/network_vlan_ranges').with_ensure('absent') end end @@ -80,6 +81,79 @@ describe 'neutron::plugins::ovs' do end end + context 'with vxlan tunneling' do + let :params do + { :tenant_network_type => 'vxlan', + :vxlan_udp_port => '4789'} + end + + before do + params.delete(:network_vlan_ranges) + end + + it 'should perform vxlan network configuration' do + should contain_neutron_plugin_ovs('OVS/tenant_network_type').with_value(params[:tenant_network_type]) + should contain_neutron_plugin_ovs('OVS/vxlan_udp_port').with_value(params[:vxlan_udp_port]) + should contain_neutron_plugin_ovs('OVS/network_vlan_ranges').with_ensure('absent') + end + end + + context 'with vxlan tunnelling using bad vxlan_udp_port' do + let :params do + { :tenant_network_type => 'vxlan', + :vxlan_udp_port => '1',} + end + + it 'should fail if invalid port is passed' do + expect { subject }.to raise_error(Puppet::Error, /vxlan udp port is invalid./) + end + end + + context 'with vxlan tunnelling using bad tunnel_id_ranges' do + let :params do + { :tenant_network_type => 'vxlan', + :tunnel_id_ranges => '100:9',} + end + + it 'should fail if invalid id range is passed' do + expect { subject }.to raise_error(Puppet::Error, /tunnel id ranges are invalid./) + end + end + + context 'with vxlan tunneling and provider networks using bad network_vlan_ranges' do + let :params do + { :tenant_network_type => 'vxlan', + :network_vlan_ranges => 'physnet1:200:1'} + end + + it 'should fail if invalid vlan range is passed' do + expect { subject }.to raise_error(Puppet::Error, /network vlan ranges are invalid./) + end + end + + context 'with vxlan tunneling using bad multiple network_vlan_ranges' do + let :params do + { :tenant_network_type => 'vxlan', + :network_vlan_ranges => ['physnet1:0:100', 'physnet2:1000:1']} + end + + it 'should fail if invalid network vlan range is passed' do + expect { subject }.to raise_error(Puppet::Error, /network vlan ranges are invalid/) + end + end + + context 'with vxlan tunneling and provider networks' do + let :params do + { :tenant_network_type => 'vxlan', + :network_vlan_ranges => 'physnet1:1000:2000'} + end + + it 'should perform vxlan network configuration' do + should contain_neutron_plugin_ovs('OVS/network_vlan_ranges').with_value(params[:network_vlan_ranges]) + should contain_neutron_plugin_ovs('OVS/tenant_network_type').with_value(params[:tenant_network_type]) + end + end + context 'with a flat network' do let :params do { :tenant_network_type => 'flat'} @@ -106,7 +180,7 @@ describe 'neutron::plugins::ovs' do end let :params do - { :network_vlan_ranges => 'test' } + { :network_vlan_ranges => 'physnet1:1000:2000' } end let :platform_params do