Add ML2 plugin support

This patch aims to support:
- ml2 configuration for Open-vSwitch & Linux Bridge plugins
- mechanism drivers: flat, gre, vlan vxlan
- l2 population support for OVS & linux bridge plugins

implement blueprint ml2-support
Change-Id: I9a4224f899e95411c509f583bf04dfc4dd0de25b
Signed-off-by: Emilien Macchi <emilien.macchi@enovance.com>
This commit is contained in:
Emilien Macchi 2013-09-25 18:02:53 +02:00
parent c0764c5198
commit 16f279f1e4
9 changed files with 569 additions and 0 deletions

View File

@ -33,6 +33,14 @@ class { 'neutron::plugins::ovs':
tenant_network_type => 'gre',
}
# ml2 plugin with vxlan as ml2 driver and ovs as mechanism driver
class { 'neutron::plugins::ml2':
type_drivers => ['vxlan'],
tenant_network_types => ['vxlan'],
vxlan_group => '239.1.1.1',
mechanism_drivers => ['openvswitch'],
vni_ranges => ['0:300']
}
### Compute Nodes:
# Generally, any machine with a neutron element running on it talks

View File

@ -0,0 +1,22 @@
Puppet::Type.type(:neutron_plugin_ml2).provide(
:ini_setting,
:parent => Puppet::Type.type(:ini_setting).provider(:ruby)
) do
def section
resource[:name].split('/', 2).first
end
def setting
resource[:name].split('/', 2).last
end
def separator
'='
end
def file_path
'/etc/neutron/plugins/ml2/ml2_conf.ini'
end
end

View File

@ -0,0 +1,20 @@
Puppet::Type.newtype(:neutron_plugin_ml2) do
ensurable
newparam(:name, :namevar => true) do
desc 'Section/setting name to manage from ml2_conf.ini'
newvalues(/\S+\/\S+/)
end
autorequire(:package) do ['neutron'] end
newproperty(:value) do
desc 'The value of the setting to be defined.'
munge do |value|
value = value.to_s.strip
value.capitalize! if value =~ /^(true|false)$/i
value
end
end
end

146
manifests/plugins/ml2.pp Normal file
View File

@ -0,0 +1,146 @@
#
# 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.
# Configure the neutron server to use the ML2 plugin.
# This configures the plugin for the API server, but does nothing
# about configuring the agents that must also run and share a config
# file with the OVS plugin if both are on the same machine.
#
# === Parameters
#
# [*type_drivers*]
# (optional) List of network type driver entrypoints to be loaded
# from the neutron.ml2.type_drivers namespace.
# Could be an array that can have these elements:
# local, flat, vlan, gre, vxlan
# Defaults to ['local', 'flat', 'vlan', 'gre', 'vxlan'].
#
# [*tenant_network_types*]
# (optional) Ordered list of network_types to allocate as tenant networks.
# The value 'local' is only useful for single-box testing
# but provides no connectivity between hosts.
# Should be an array that can have these elements:
# local, flat, vlan, gre, vxlan
# Defaults to ['local', 'flat', 'vlan', 'gre', 'vxlan'].
#
# [*mechanism_drivers*]
# (optional) An ordered list of networking mechanism driver
# entrypoints to be loaded from the neutron.ml2.mechanism_drivers namespace.
# Should be an array that can have these elements:
# logger, test, linuxbridge, openvswitch, hyperv, ncs, arista, cisco_nexus,
# l2population.
# Default to ['openvswitch', 'linuxbridge'].
#
# [*flat_networks*]
# (optional) List of physical_network names with which flat networks
# can be created. Use * to allow flat networks with arbitrary
# physical_network names.
# Should be an array.
# Default to *.
#
# [*network_vlan_ranges*]
# (optional) List of <physical_network>:<vlan_min>:<vlan_max> or
# <physical_network> specifying physical_network names
# usable for VLAN provider and tenant networks, as
# well as ranges of VLAN tags on each available for
# allocation to tenant networks.
# Should be an array with vlan_min = 1 & vlan_max = 4094 (IEEE 802.1Q)
# Default to empty.
#
# [*tunnel_id_ranges*]
# (optional) Comma-separated list of <tun_min>:<tun_max> tuples
# enumerating ranges of GRE tunnel IDs that are
# available for tenant network allocation
# Should be an array with tun_max +1 - tun_min > 1000000
# Default to empty.
#
# [*vxlan_group*]
# (optional) Multicast group for VXLAN.
# Multicast group for VXLAN. If unset, disables VXLAN enable sending allocate
# broadcast traffic to this multicast group. When left unconfigured, will
# disable multicast VXLAN mode
# Should be an Multicast IP (v4 or v6) address.
# Default to 'None'.
#
# [*vni_ranges*]
# (optional) Comma-separated list of <vni_min>:<vni_max> tuples
# enumerating ranges of VXLAN VNI IDs that are
# available for tenant network allocation.
# Min value is 0 and Max value is 16777215.
# Default to empty.
#
class neutron::plugins::ml2 (
$type_drivers = ['local', 'flat', 'vlan', 'gre', 'vxlan'],
$tenant_network_types = ['local', 'flat', 'vlan', 'gre', 'vxlan'],
$mechanism_drivers = ['openvswitch', 'linuxbridge'],
$flat_networks = ['*'],
$network_vlan_ranges = ['10:50'],
$tunnel_id_ranges = ['20:100'],
$vxlan_group = '224.0.0.1',
$vni_ranges = ['10:100']
) {
include neutron::params
# test mechanism drivers
validate_array($mechanism_drivers)
if ! $mechanism_drivers {
warning('Without networking mechanism driver, ml2 will not communicate with L2 agents')
}
neutron::plugins::ml2::driver { $type_drivers:
flat_networks => $flat_networks,
tunnel_id_ranges => $tunnel_id_ranges,
network_vlan_ranges => $network_vlan_ranges,
vni_ranges => $vni_ranges,
vxlan_group => $vxlan_group,
}
# Configure ml2_conf.ini
neutron_plugin_ml2 {
'ml2/type_drivers': value => join($type_drivers, ',');
'ml2/tenant_network_types': value => join($tenant_network_types, ',');
'ml2/mechanism_drivers': value => join($mechanism_drivers, ',');
}
# Specific plugin configuration
if ('openvswitch' in $mechanism_drivers) and ('l2population' in $mechanism_drivers) {
neutron_plugin_ovs {
'agent/l2_population': value => true;
}
} else {
neutron_plugin_ovs {
'agent/l2_population': value => false;
}
}
if ('linuxbridge' in $mechanism_drivers) and ('l2population' in $mechanism_drivers) {
neutron_plugin_linuxbridge {
'vxlan/enable_vxlan': value => true;
'vxlan/l2_population': value => true;
}
}
if $::osfamily == 'Redhat' {
file {'/etc/neutron/plugin.ini':
ensure => link,
target => '/etc/neutron/plugins/ml2/ml2_conf.ini',
require => Package['openstack-neutron']
}
}
}

View File

@ -0,0 +1,90 @@
#
# 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.
#
# neutron::plugins::ml2::drivers used by neutron::plugins::ml2
#
define neutron::plugins::ml2::driver (
$flat_networks,
$tunnel_id_ranges,
$network_vlan_ranges,
$vni_ranges,
$vxlan_group
){
if ($name == 'flat') {
neutron_plugin_ml2 {
'ml2_type_flat/flat_networks': value => join($flat_networks, ',');
}
}
elsif ($name == 'gre') {
# tunnel_id_ranges is required in gre
if ! $tunnel_id_ranges {
fail('when gre is part of type_drivers, tunnel_id_ranges should be given.')
}
neutron::plugins::ml2::validate_tunnel_id_ranges { $tunnel_id_ranges:; }
neutron_plugin_ml2 {
'ml2_type_gre/tunnel_id_ranges': value => join($tunnel_id_ranges, ',');
}
}
elsif ($name == 'vlan') {
# network_vlan_ranges is required in vlan
if ! $network_vlan_ranges {
fail('when vlan is part of type_drivers, network_vlan_ranges should be given.')
}
neutron::plugins::ml2::validate_network_vlan_ranges { $network_vlan_ranges:; }
neutron_plugin_ml2 {
'ml2_type_vlan/network_vlan_ranges': value => join($network_vlan_ranges, ',');
}
}
elsif ($name == 'vxlan') {
# vni_ranges and vxlan_group are required in vxlan
if (! $vni_ranges) or (! $vxlan_group) {
fail('when vxlan is part of type_drivers, vni_ranges and vxlan_group should be given.')
}
# test multicast ip address (ipv4 else ipv6):
case $vxlan_group {
/^2[\d.]+$/: {
case $vxlan_group {
/^(22[4-9]|23[0-9])\.(\d+)\.(\d+)\.(\d+)$/: { }
default: { }
}
}
/^ff[\d.]+$/: { }
default: {
fail("${vxlan_group} is not valid for vxlan_group.")
}
}
neutron::plugins::ml2::validate_vni_ranges { $vni_ranges: }
neutron_plugin_ml2 {
'ml2_type_vxlan/vxlan_group': value => $vxlan_group;
'ml2_type_vxlan/vni_ranges': value => join($vni_ranges, ',');
}
}
elsif ($name == 'local') {
warning('local type_driver is useful only for single-box, because it provides no connectivity between hosts')
}
else {
# detect an invalid type_drivers value
fail('type_driver unknown.')
}
}

View File

@ -0,0 +1,30 @@
#
# 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 for VLAN 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.')
}
}

View File

@ -0,0 +1,30 @@
#
# 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

@ -0,0 +1,34 @@
#
# 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

@ -0,0 +1,189 @@
#
# 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.
#
# Unit tests for neutron::plugins::ml2 class
#
require 'spec_helper'
describe 'neutron::plugins::ml2' do
let :default_params do
{ :type_drivers => ['local', 'flat', 'vlan', 'gre', 'vxlan'],
:tenant_network_types => ['local', 'flat', 'vlan', 'gre', 'vxlan'],
:mechanism_drivers => ['openvswitch', 'linuxbridge'],
:flat_networks => ['*'],
:network_vlan_ranges => ['10:50'],
:tunnel_id_ranges => ['20:100'],
:vxlan_group => '224.0.0.1',
:vni_ranges => ['10:100'] }
end
let :params do
{}
end
shared_examples_for 'neutron plugin ml2' do
let :p do
default_params.merge(params)
end
it { should include_class('neutron::params') }
it 'configures ml2_conf.ini' do
should contain_neutron_plugin_ml2('ml2/type_drivers').with_value(p[:type_drivers].join(','))
should contain_neutron_plugin_ml2('ml2/tenant_network_types').with_value(p[:tenant_network_types].join(','))
should contain_neutron_plugin_ml2('ml2/mechanism_drivers').with_value(p[:mechanism_drivers].join(','))
end
it 'configures ovs plugin' do
should_not contain_neutron_plugin_ovs('agent/l2_population').with('value' => true)
end
it 'configures linux bridge plugin' do
should_not contain_neutron_plugin_linuxbridge('vxlan/enable_vxlan').with('value' => true)
should_not contain_neutron_plugin_linuxbridge('vxlan/l2_population').with('value' => true)
end
context 'configure ml2 with bad driver value' do
before :each do
params.merge!(:type_drivers => ['foobar'])
end
it 'should fails to configure ml2 because foobar is not a valid driver' do
expect { subject }.to raise_error(Puppet::Error, /type_driver unknown./)
end
end
context 'when using flat driver' do
before :each do
params.merge!(:flat_networks => ['eth1', 'eth2'])
end
it 'should configure flat_networks' do
should contain_neutron_plugin_ml2('ml2_type_flat/flat_networks').with_value(p[:flat_networks].join(','))
end
end
context 'when using gre driver with valid values' do
before :each do
params.merge!(:tunnel_id_ranges => ['0:20', '40:60'])
end
it 'should configure gre_networks with valid ranges' do
should contain_neutron_plugin_ml2('ml2_type_gre/tunnel_id_ranges').with_value(p[:tunnel_id_ranges].join(','))
end
end
context 'when using gre driver with invalid values' do
before :each do
params.merge!(:tunnel_id_ranges => ['0:20', '40:100000000'])
end
it 'should fails to configure gre_networks because of too big range' do
expect { subject }.to raise_error(Puppet::Error, /tunnel id ranges are to large./)
end
end
context 'when using vlan driver with valid values' do
before :each do
params.merge!(:network_vlan_ranges => ['1:20', '400:4094'])
end
it 'should configure vlan_networks with 1:20 and 400:4094 VLAN ranges' do
should contain_neutron_plugin_ml2('ml2_type_vlan/network_vlan_ranges').with_value(p[:network_vlan_ranges].join(','))
end
end
context 'when using vlan driver with invalid vlan id' do
before :each do
params.merge!(:network_vlan_ranges => ['1:20', '400:4099'])
end
it 'should fails to configure vlan_networks because of 400:4099 VLAN range' do
expect { subject }.to raise_error(Puppet::Error, /vlan id are invalid./)
end
end
context 'when using vlan driver with invalid vlan range' do
before :each do
params.merge!(:network_vlan_ranges => ['2938:1'])
end
it 'should fails to configure network_vlan_ranges with 2938:1 range' do
expect { subject }.to raise_error(Puppet::Error, /vlan ranges are invalid./)
end
end
context 'when using vxlan driver with valid values' do
before :each do
params.merge!(:vni_ranges => ['40:300', '500:1000'], :vxlan_group => '224.1.1.1')
end
it 'should configure vxlan_networks with 224.1.1.1 vxlan group' do
should contain_neutron_plugin_ml2('ml2_type_vxlan/vni_ranges').with_value(p[:vni_ranges].join(','))
should contain_neutron_plugin_ml2('ml2_type_vxlan/vxlan_group').with_value(p[:vxlan_group])
end
end
context 'when using vxlan driver with invalid vxlan group' do
before :each do
params.merge!(:vxlan_group => '192.1.1.1')
end
it 'should fails to configure vxlan_group with 192.1.1.1 vxlan group' do
expect { subject }.to raise_error(Puppet::Error, /is not valid for vxlan_group./)
end
end
context 'when using vxlan driver with invalid vni_range' do
before :each do
params.merge!(:vni_ranges => ['2938:1'])
end
it 'should fails to configure vni_ranges with 2938:1 range' do
expect { subject }.to raise_error(Puppet::Error, /vni ranges are invalid./)
end
end
context 'when using l2population with ovs' do
before :each do
params.merge!(:mechanism_drivers => ['openvswitch','l2population'])
end
it 'should set l2_population flag as true' do
should contain_neutron_plugin_ovs('agent/l2_population').with_value('true')
end
end
context 'when using l2population with linuxbridge' do
before :each do
params.merge!(:mechanism_drivers => ['linuxbridge','l2population'])
end
it 'should set l2_population flag as true' do
should contain_neutron_plugin_linuxbridge('vxlan/enable_vxlan').with_value('true')
should contain_neutron_plugin_linuxbridge('vxlan/l2_population').with_value('true')
end
end
end
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian' }
end
it_configures 'neutron plugin ml2'
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat' }
end
it_configures 'neutron plugin ml2'
end
end