VXLAN support

This patch is implementing support for VXLAN tunnel
type for OVS plugin.

Refactored neutron::plugins::ml2::validate_* to functions
so they can be used in other manifests in module.

Change-Id: Ic51ed794b27069809a151dc365ca108c8300c277
This commit is contained in:
Martin Magr 2013-11-07 17:05:18 +01:00
parent 37d1c5b810
commit 766561df83
12 changed files with 275 additions and 97 deletions

View File

@ -0,0 +1,44 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
# Martin Magr <mmagr@redhat.com>
#
# 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

View File

@ -0,0 +1,44 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
# Martin Magr <mmagr@redhat.com>
#
# 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

View File

@ -0,0 +1,47 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
# Martin Magr <mmagr@redhat.com>
#
# 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

View File

@ -2,6 +2,7 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
# Martin Magr <mmagr@redhat.com>
#
# 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

View File

@ -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;

View File

@ -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']

View File

@ -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;

View File

@ -1,30 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# 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.')
}
}

View File

@ -1,34 +0,0 @@
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# 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.')
}
}
}

View File

@ -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;
}
}
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 == 'vlan') or ($tenant_network_type == 'flat') {
if ! $network_vlan_ranges {
if $tenant_network_type in ['vlan', 'flat'] {
fail('When using the vlan network type, network_vlan_ranges is required')
}
} else {
if ! $network_vlan_ranges {
neutron_plugin_ovs { 'OVS/network_vlan_ranges': ensure => absent }
}
}
# This might be set by the user for the gre case where
} else {
# This might be set by the user for the gre or vxlan case where
# provider networks are in use
if $network_vlan_ranges {
validate_network_vlan_ranges($network_vlan_ranges)
neutron_plugin_ovs {
'OVS/network_vlan_ranges': value => $network_vlan_ranges
}

View File

@ -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

View File

@ -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