Merge "Add VXLAN tunneling support for the ML2 plugin"
This commit is contained in:
commit
3cd25081aa
@ -3,15 +3,22 @@
|
||||
# (ListOpt) List of network type driver entrypoints to be loaded from
|
||||
# the quantum.ml2.type_drivers namespace.
|
||||
#
|
||||
# type_drivers = local,flat,vlan,gre
|
||||
# Example: type_drivers = flat,vlan,gre
|
||||
# type_drivers = local,flat,vlan,gre,vxlan
|
||||
# Example: type_drivers = flat,vlan,gre,vxlan
|
||||
|
||||
# (ListOpt) Ordered list of network_types to allocate as tenant
|
||||
# networks. The default value 'local' is useful for single-box testing
|
||||
# but provides no connectivity between hosts.
|
||||
#
|
||||
# tenant_network_types = local
|
||||
# Example: tenant_network_types = vlan,gre
|
||||
# Example: tenant_network_types = vlan,gre,vxlan
|
||||
|
||||
# (StrOpt) Multicast group for the VXLAN interface. When configured, will
|
||||
# enable sending all broadcast traffic to this multicast group. When left
|
||||
# unconfigured, will disable multicast VXLAN mode.
|
||||
#
|
||||
# vxlan_group =
|
||||
# Example: vxlan_group = 239.1.1.1
|
||||
|
||||
# (ListOpt) Ordered list of networking mechanism driver entrypoints
|
||||
# to be loaded from the neutron.ml2.mechanism_drivers namespace.
|
||||
|
@ -0,0 +1,69 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2013 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""DB Migration for ML2 VXLAN Type Driver
|
||||
|
||||
Revision ID: 477a4488d3f4
|
||||
Revises: 20ae61555e95
|
||||
Create Date: 2013-07-09 14:14:33.158502
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '477a4488d3f4'
|
||||
down_revision = '20ae61555e95'
|
||||
|
||||
# Change to ['*'] if this migration applies to all plugins
|
||||
|
||||
migration_for_plugins = [
|
||||
'neutron.plugins.ml2.plugin.Ml2Plugin'
|
||||
]
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
from neutron.db import migration
|
||||
|
||||
|
||||
def upgrade(active_plugin=None, options=None):
|
||||
if not migration.should_run(active_plugin, migration_for_plugins):
|
||||
return
|
||||
|
||||
op.create_table(
|
||||
'ml2_vxlan_allocations',
|
||||
sa.Column('vxlan_vni', sa.Integer, nullable=False,
|
||||
autoincrement=False),
|
||||
sa.Column('allocated', sa.Boolean, nullable=False),
|
||||
sa.PrimaryKeyConstraint('vxlan_vni')
|
||||
)
|
||||
|
||||
op.create_table(
|
||||
'ml2_vxlan_endpoints',
|
||||
sa.Column('ip_address', sa.String(length=64)),
|
||||
sa.Column('udp_port', sa.Integer(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('ip_address'),
|
||||
sa.PrimaryKeyConstraint('udp_port')
|
||||
)
|
||||
|
||||
|
||||
def downgrade(active_plugin=None, options=None):
|
||||
if not migration.should_run(active_plugin, migration_for_plugins):
|
||||
return
|
||||
|
||||
op.drop_table('ml2_vxlan_allocations')
|
||||
op.drop_table('ml2_vxlan_endpoint')
|
@ -20,7 +20,7 @@ from neutron import scheduler
|
||||
|
||||
ml2_opts = [
|
||||
cfg.ListOpt('type_drivers',
|
||||
default=['local', 'flat', 'vlan', 'gre'],
|
||||
default=['local', 'flat', 'vlan', 'gre', 'vxlan'],
|
||||
help=_("List of network type driver entrypoints to be loaded "
|
||||
"from the neutron.ml2.type_drivers namespace.")),
|
||||
cfg.ListOpt('tenant_network_types',
|
||||
|
@ -26,6 +26,8 @@ from neutron.plugins.ml2.drivers import type_tunnel
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
TYPE_GRE = 'gre'
|
||||
|
||||
gre_opts = [
|
||||
cfg.ListOpt('tunnel_id_ranges',
|
||||
default=[],
|
||||
@ -60,11 +62,15 @@ class GreTypeDriver(api.TypeDriver,
|
||||
type_tunnel.TunnelTypeDriver):
|
||||
|
||||
def get_type(self):
|
||||
return type_tunnel.TYPE_GRE
|
||||
return TYPE_GRE
|
||||
|
||||
def initialize(self):
|
||||
self.gre_id_ranges = []
|
||||
self._parse_gre_id_ranges()
|
||||
self._parse_tunnel_ranges(
|
||||
cfg.CONF.ml2_type_gre.tunnel_id_ranges,
|
||||
self.gre_id_ranges,
|
||||
TYPE_GRE
|
||||
)
|
||||
self._sync_gre_allocations()
|
||||
|
||||
def validate_provider_segment(self, segment):
|
||||
@ -109,7 +115,7 @@ class GreTypeDriver(api.TypeDriver,
|
||||
LOG.debug(_("Allocating gre tunnel id %(gre_id)s"),
|
||||
{'gre_id': alloc.gre_id})
|
||||
alloc.allocated = True
|
||||
return {api.NETWORK_TYPE: type_tunnel.TYPE_GRE,
|
||||
return {api.NETWORK_TYPE: TYPE_GRE,
|
||||
api.PHYSICAL_NETWORK: None,
|
||||
api.SEGMENTATION_ID: alloc.gre_id}
|
||||
|
||||
@ -134,21 +140,6 @@ class GreTypeDriver(api.TypeDriver,
|
||||
except sa_exc.NoResultFound:
|
||||
LOG.warning(_("gre_id %s not found"), gre_id)
|
||||
|
||||
def _parse_gre_id_ranges(self):
|
||||
for entry in cfg.CONF.ml2_type_gre.tunnel_id_ranges:
|
||||
entry = entry.strip()
|
||||
try:
|
||||
tun_min, tun_max = entry.split(':')
|
||||
tun_min = tun_min.strip()
|
||||
tun_max = tun_max.strip()
|
||||
self.gre_id_ranges.append((int(tun_min), int(tun_max)))
|
||||
except ValueError as ex:
|
||||
LOG.error(_("Invalid tunnel ID range: '%(range)s' - %(e)s. "
|
||||
"Agent terminated!"),
|
||||
{'range': cfg.CONF.ml2_type_gre.tunnel_id_ranges,
|
||||
'e': ex})
|
||||
LOG.info(_("gre ID ranges: %s"), self.gre_id_ranges)
|
||||
|
||||
def _sync_gre_allocations(self):
|
||||
"""Synchronize gre_allocations table with configured tunnel ranges."""
|
||||
|
||||
|
@ -22,8 +22,6 @@ LOG = log.getLogger(__name__)
|
||||
|
||||
TUNNEL = 'tunnel'
|
||||
|
||||
TYPE_GRE = 'gre'
|
||||
|
||||
|
||||
class TunnelTypeDriver(object):
|
||||
"""Define stable abstract interface for ML2 type drivers.
|
||||
@ -50,6 +48,21 @@ class TunnelTypeDriver(object):
|
||||
"""
|
||||
pass
|
||||
|
||||
def _parse_tunnel_ranges(self, tunnel_ranges, current_range, tunnel_type):
|
||||
for entry in tunnel_ranges:
|
||||
entry = entry.strip()
|
||||
try:
|
||||
tun_min, tun_max = entry.split(':')
|
||||
tun_min = tun_min.strip()
|
||||
tun_max = tun_max.strip()
|
||||
current_range.append((int(tun_min), int(tun_max)))
|
||||
except ValueError as ex:
|
||||
LOG.error(_("Invalid tunnel ID range: '%(range)s' - %(e)s. "
|
||||
"Agent terminated!"),
|
||||
{'range': tunnel_ranges, 'e': ex})
|
||||
LOG.info(_("%(type)s ID ranges: %(range)s"),
|
||||
{'type': tunnel_type, 'range': current_range})
|
||||
|
||||
|
||||
class TunnelRpcCallbackMixin(object):
|
||||
|
||||
|
215
neutron/plugins/ml2/drivers/type_vxlan.py
Normal file
215
neutron/plugins/ml2/drivers/type_vxlan.py
Normal file
@ -0,0 +1,215 @@
|
||||
# Copyright (c) 2013 OpenStack Foundation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
# @author: Kyle Mestery, Cisco Systems, Inc.
|
||||
|
||||
from oslo.config import cfg
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.orm import exc as sa_exc
|
||||
|
||||
from neutron.common import exceptions as exc
|
||||
from neutron.db import api as db_api
|
||||
from neutron.db import model_base
|
||||
from neutron.openstack.common import log
|
||||
from neutron.plugins.ml2 import driver_api as api
|
||||
from neutron.plugins.ml2.drivers import type_tunnel
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
TYPE_VXLAN = 'vxlan'
|
||||
VXLAN_UDP_PORT = 4789
|
||||
MAX_VXLAN_VNI = 16777215
|
||||
|
||||
vxlan_opts = [
|
||||
cfg.ListOpt('vni_ranges',
|
||||
default=[],
|
||||
help=_("Comma-separated list of <vni_min>:<vni_max> tuples "
|
||||
"enumerating ranges of VXLAN VNI IDs that are "
|
||||
"available for tenant network allocation")),
|
||||
cfg.StrOpt('vxlan_group', default=None,
|
||||
help=_("Multicast group for VXLAN. If unset, disables VXLAN "
|
||||
"multicast mode.")),
|
||||
]
|
||||
|
||||
cfg.CONF.register_opts(vxlan_opts, "ml2_type_vxlan")
|
||||
|
||||
|
||||
class VxlanAllocation(model_base.BASEV2):
|
||||
|
||||
__tablename__ = 'ml2_vxlan_allocations'
|
||||
|
||||
vxlan_vni = sa.Column(sa.Integer, nullable=False, primary_key=True,
|
||||
autoincrement=False)
|
||||
allocated = sa.Column(sa.Boolean, nullable=False, default=False)
|
||||
|
||||
|
||||
class VxlanEndpoints(model_base.BASEV2):
|
||||
"""Represents tunnel endpoint in RPC mode."""
|
||||
__tablename__ = 'ml2_vxlan_endpoints'
|
||||
|
||||
ip_address = sa.Column(sa.String(64), primary_key=True)
|
||||
udp_port = sa.Column(sa.Integer, primary_key=True, nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
return "<VxlanTunnelEndpoint(%s)>" % self.ip_address
|
||||
|
||||
|
||||
class VxlanTypeDriver(api.TypeDriver,
|
||||
type_tunnel.TunnelTypeDriver):
|
||||
|
||||
def get_type(self):
|
||||
return TYPE_VXLAN
|
||||
|
||||
def initialize(self):
|
||||
self.vxlan_vni_ranges = []
|
||||
self._parse_tunnel_ranges(
|
||||
cfg.CONF.ml2_type_vxlan.vni_ranges,
|
||||
self.vxlan_vni_ranges,
|
||||
TYPE_VXLAN
|
||||
)
|
||||
self._sync_vxlan_allocations()
|
||||
|
||||
def validate_provider_segment(self, segment):
|
||||
physical_network = segment.get(api.PHYSICAL_NETWORK)
|
||||
if physical_network:
|
||||
msg = _("provider:physical_network specified for VXLAN "
|
||||
"network")
|
||||
raise exc.InvalidInput(error_message=msg)
|
||||
|
||||
segmentation_id = segment.get(api.SEGMENTATION_ID)
|
||||
if segmentation_id is None:
|
||||
msg = _("segmentation_id required for VXLAN provider network")
|
||||
raise exc.InvalidInput(error_message=msg)
|
||||
|
||||
def reserve_provider_segment(self, session, segment):
|
||||
segmentation_id = segment.get(api.SEGMENTATION_ID)
|
||||
with session.begin(subtransactions=True):
|
||||
try:
|
||||
alloc = (session.query(VxlanAllocation).
|
||||
filter_by(vxlan_vni=segmentation_id).
|
||||
with_lockmode('update').
|
||||
one())
|
||||
if alloc.allocated:
|
||||
raise exc.TunnelIdInUse(tunnel_id=segmentation_id)
|
||||
LOG.debug(_("Reserving specific vxlan tunnel %s from pool"),
|
||||
segmentation_id)
|
||||
alloc.allocated = True
|
||||
except sa_exc.NoResultFound:
|
||||
LOG.debug(_("Reserving specific vxlan tunnel %s outside pool"),
|
||||
segmentation_id)
|
||||
alloc = VxlanAllocation(vxlan_vni=segmentation_id)
|
||||
alloc.allocated = True
|
||||
session.add(alloc)
|
||||
|
||||
def allocate_tenant_segment(self, session):
|
||||
with session.begin(subtransactions=True):
|
||||
alloc = (session.query(VxlanAllocation).
|
||||
filter_by(allocated=False).
|
||||
with_lockmode('update').
|
||||
first())
|
||||
if alloc:
|
||||
LOG.debug(_("Allocating vxlan tunnel vni %(vxlan_vni)s"),
|
||||
{'vxlan_vni': alloc.vxlan_vni})
|
||||
alloc.allocated = True
|
||||
return {api.NETWORK_TYPE: TYPE_VXLAN,
|
||||
api.PHYSICAL_NETWORK: None,
|
||||
api.SEGMENTATION_ID: alloc.vxlan_vni}
|
||||
|
||||
def release_segment(self, session, segment):
|
||||
vxlan_vni = segment[api.SEGMENTATION_ID]
|
||||
with session.begin(subtransactions=True):
|
||||
try:
|
||||
alloc = (session.query(VxlanAllocation).
|
||||
filter_by(vxlan_vni=vxlan_vni).
|
||||
with_lockmode('update').
|
||||
one())
|
||||
alloc.allocated = False
|
||||
for low, high in self.vxlan_vni_ranges:
|
||||
if low <= vxlan_vni <= high:
|
||||
LOG.debug(_("Releasing vxlan tunnel %s to pool"),
|
||||
vxlan_vni)
|
||||
break
|
||||
else:
|
||||
session.delete(alloc)
|
||||
LOG.debug(_("Releasing vxlan tunnel %s outside pool"),
|
||||
vxlan_vni)
|
||||
except sa_exc.NoResultFound:
|
||||
LOG.warning(_("vxlan_vni %s not found"), vxlan_vni)
|
||||
|
||||
def _sync_vxlan_allocations(self):
|
||||
"""
|
||||
Synchronize vxlan_allocations table with configured tunnel ranges.
|
||||
"""
|
||||
|
||||
# determine current configured allocatable vnis
|
||||
vxlan_vnis = set()
|
||||
for tun_min, tun_max in self.vxlan_vni_ranges:
|
||||
if tun_max + 1 - tun_min > MAX_VXLAN_VNI:
|
||||
LOG.error(_("Skipping unreasonable VXLAN VNI range "
|
||||
"%(tun_min)s:%(tun_max)s"),
|
||||
{'tun_min': tun_min, 'tun_max': tun_max})
|
||||
else:
|
||||
vxlan_vnis |= set(xrange(tun_min, tun_max + 1))
|
||||
|
||||
session = db_api.get_session()
|
||||
with session.begin(subtransactions=True):
|
||||
# remove from table unallocated tunnels not currently allocatable
|
||||
allocs = session.query(VxlanAllocation)
|
||||
for alloc in allocs:
|
||||
try:
|
||||
# see if tunnel is allocatable
|
||||
vxlan_vnis.remove(alloc.vxlan_vni)
|
||||
except KeyError:
|
||||
# it's not allocatable, so check if its allocated
|
||||
if not alloc.allocated:
|
||||
# it's not, so remove it from table
|
||||
LOG.debug(_("Removing tunnel %s from pool"),
|
||||
alloc.vxlan_vni)
|
||||
session.delete(alloc)
|
||||
|
||||
# add missing allocatable tunnels to table
|
||||
for vxlan_vni in sorted(vxlan_vnis):
|
||||
alloc = VxlanAllocation(vxlan_vni=vxlan_vni)
|
||||
session.add(alloc)
|
||||
|
||||
def get_vxlan_allocation(self, session, vxlan_vni):
|
||||
with session.begin(subtransactions=True):
|
||||
return session.query(VxlanAllocation).filter_by(
|
||||
vxlan_vni=vxlan_vni).first()
|
||||
|
||||
def get_endpoints(self):
|
||||
"""Get every vxlan endpoints from database."""
|
||||
|
||||
LOG.debug(_("get_vxlan_endpoints() called"))
|
||||
session = db_api.get_session()
|
||||
|
||||
with session.begin(subtransactions=True):
|
||||
vxlan_endpoints = session.query(VxlanEndpoints)
|
||||
return [{'ip_address': vxlan_endpoint.ip_address,
|
||||
'udp_port': vxlan_endpoint.udp_port}
|
||||
for vxlan_endpoint in vxlan_endpoints]
|
||||
|
||||
def add_endpoint(self, ip, udp_port=VXLAN_UDP_PORT):
|
||||
LOG.debug(_("add_vxlan_endpoint() called for ip %s"), ip)
|
||||
session = db_api.get_session()
|
||||
with session.begin(subtransactions=True):
|
||||
try:
|
||||
vxlan_endpoint = (session.query(VxlanEndpoints).
|
||||
filter_by(ip_address=ip).
|
||||
with_lockmode('update').one())
|
||||
except sa_exc.NoResultFound:
|
||||
vxlan_endpoint = VxlanEndpoints(ip_address=ip,
|
||||
udp_port=udp_port)
|
||||
session.add(vxlan_endpoint)
|
||||
return vxlan_endpoint
|
196
neutron/tests/unit/ml2/test_type_vxlan.py
Normal file
196
neutron/tests/unit/ml2/test_type_vxlan.py
Normal file
@ -0,0 +1,196 @@
|
||||
# Copyright (c) 2013 OpenStack Foundation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
# @author: Kyle Mestery, Cisco Systems, Inc.
|
||||
|
||||
from oslo.config import cfg
|
||||
import testtools
|
||||
from testtools import matchers
|
||||
|
||||
from neutron.common import exceptions as exc
|
||||
from neutron.db import api as db
|
||||
from neutron.plugins.ml2 import db as ml2_db
|
||||
from neutron.plugins.ml2 import driver_api as api
|
||||
from neutron.plugins.ml2.drivers import type_vxlan
|
||||
from neutron.tests import base
|
||||
|
||||
|
||||
TUNNEL_IP_ONE = "10.10.10.10"
|
||||
TUNNEL_IP_TWO = "10.10.10.20"
|
||||
TUN_MIN = 100
|
||||
TUN_MAX = 109
|
||||
TUNNEL_RANGES = [(TUN_MIN, TUN_MAX)]
|
||||
UPDATED_TUNNEL_RANGES = [(TUN_MIN + 5, TUN_MAX + 5)]
|
||||
INVALID_VXLAN_VNI = 7337
|
||||
MULTICAST_GROUP = "239.1.1.1"
|
||||
VXLAN_UDP_PORT_ONE = 9999
|
||||
VXLAN_UDP_PORT_TWO = 8888
|
||||
|
||||
|
||||
class VxlanTypeTest(base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(VxlanTypeTest, self).setUp()
|
||||
ml2_db.initialize()
|
||||
cfg.CONF.set_override('vni_ranges', [TUNNEL_RANGES],
|
||||
group='ml2_type_vxlan')
|
||||
cfg.CONF.set_override('vxlan_group', MULTICAST_GROUP,
|
||||
group='ml2_type_vxlan')
|
||||
self.driver = type_vxlan.VxlanTypeDriver()
|
||||
self.driver.vxlan_vni_ranges = TUNNEL_RANGES
|
||||
self.driver._sync_vxlan_allocations()
|
||||
self.session = db.get_session()
|
||||
self.addCleanup(cfg.CONF.reset)
|
||||
self.addCleanup(db.clear_db)
|
||||
|
||||
def test_vxlan_tunnel_type(self):
|
||||
self.assertEqual(self.driver.get_type(), type_vxlan.TYPE_VXLAN)
|
||||
|
||||
def test_validate_provider_segment(self):
|
||||
segment = {api.NETWORK_TYPE: 'vxlan',
|
||||
api.PHYSICAL_NETWORK: 'phys_net',
|
||||
api.SEGMENTATION_ID: None}
|
||||
|
||||
with testtools.ExpectedException(exc.InvalidInput):
|
||||
self.driver.validate_provider_segment(segment)
|
||||
|
||||
segment[api.PHYSICAL_NETWORK] = None
|
||||
with testtools.ExpectedException(exc.InvalidInput):
|
||||
self.driver.validate_provider_segment(segment)
|
||||
|
||||
def test_sync_tunnel_allocations(self):
|
||||
self.assertIsNone(
|
||||
self.driver.get_vxlan_allocation(self.session,
|
||||
(TUN_MIN - 1))
|
||||
)
|
||||
self.assertFalse(
|
||||
self.driver.get_vxlan_allocation(self.session,
|
||||
(TUN_MIN)).allocated
|
||||
)
|
||||
self.assertFalse(
|
||||
self.driver.get_vxlan_allocation(self.session,
|
||||
(TUN_MIN + 1)).allocated
|
||||
)
|
||||
self.assertFalse(
|
||||
self.driver.get_vxlan_allocation(self.session,
|
||||
(TUN_MAX - 1)).allocated
|
||||
)
|
||||
self.assertFalse(
|
||||
self.driver.get_vxlan_allocation(self.session,
|
||||
(TUN_MAX)).allocated
|
||||
)
|
||||
self.assertIsNone(
|
||||
self.driver.get_vxlan_allocation(self.session,
|
||||
(TUN_MAX + 1))
|
||||
)
|
||||
|
||||
self.driver.vxlan_vni_ranges = UPDATED_TUNNEL_RANGES
|
||||
self.driver._sync_vxlan_allocations()
|
||||
|
||||
self.assertIsNone(self.driver.
|
||||
get_vxlan_allocation(self.session,
|
||||
(TUN_MIN + 5 - 1)))
|
||||
self.assertFalse(self.driver.
|
||||
get_vxlan_allocation(self.session, (TUN_MIN + 5)).
|
||||
allocated)
|
||||
self.assertFalse(self.driver.
|
||||
get_vxlan_allocation(self.session, (TUN_MIN + 5 + 1)).
|
||||
allocated)
|
||||
self.assertFalse(self.driver.
|
||||
get_vxlan_allocation(self.session, (TUN_MAX + 5 - 1)).
|
||||
allocated)
|
||||
self.assertFalse(self.driver.
|
||||
get_vxlan_allocation(self.session, (TUN_MAX + 5)).
|
||||
allocated)
|
||||
self.assertIsNone(self.driver.
|
||||
get_vxlan_allocation(self.session,
|
||||
(TUN_MAX + 5 + 1)))
|
||||
|
||||
def test_reserve_provider_segment(self):
|
||||
segment = {api.NETWORK_TYPE: 'vxlan',
|
||||
api.PHYSICAL_NETWORK: 'None',
|
||||
api.SEGMENTATION_ID: 101}
|
||||
self.driver.reserve_provider_segment(self.session, segment)
|
||||
alloc = self.driver.get_vxlan_allocation(self.session,
|
||||
segment[api.SEGMENTATION_ID])
|
||||
self.assertTrue(alloc.allocated)
|
||||
|
||||
with testtools.ExpectedException(exc.TunnelIdInUse):
|
||||
self.driver.reserve_provider_segment(self.session, segment)
|
||||
|
||||
self.driver.release_segment(self.session, segment)
|
||||
alloc = self.driver.get_vxlan_allocation(self.session,
|
||||
segment[api.SEGMENTATION_ID])
|
||||
self.assertFalse(alloc.allocated)
|
||||
|
||||
segment[api.SEGMENTATION_ID] = 1000
|
||||
self.driver.reserve_provider_segment(self.session, segment)
|
||||
alloc = self.driver.get_vxlan_allocation(self.session,
|
||||
segment[api.SEGMENTATION_ID])
|
||||
self.assertTrue(alloc.allocated)
|
||||
|
||||
self.driver.release_segment(self.session, segment)
|
||||
alloc = self.driver.get_vxlan_allocation(self.session,
|
||||
segment[api.SEGMENTATION_ID])
|
||||
self.assertIsNone(alloc)
|
||||
|
||||
def test_allocate_tenant_segment(self):
|
||||
tunnel_ids = set()
|
||||
for x in xrange(TUN_MIN, TUN_MAX + 1):
|
||||
segment = self.driver.allocate_tenant_segment(self.session)
|
||||
self.assertThat(segment[api.SEGMENTATION_ID],
|
||||
matchers.GreaterThan(TUN_MIN - 1))
|
||||
self.assertThat(segment[api.SEGMENTATION_ID],
|
||||
matchers.LessThan(TUN_MAX + 1))
|
||||
tunnel_ids.add(segment[api.SEGMENTATION_ID])
|
||||
|
||||
segment = self.driver.allocate_tenant_segment(self.session)
|
||||
self.assertEqual(None, segment)
|
||||
|
||||
segment = {api.NETWORK_TYPE: 'vxlan',
|
||||
api.PHYSICAL_NETWORK: 'None',
|
||||
api.SEGMENTATION_ID: tunnel_ids.pop()}
|
||||
self.driver.release_segment(self.session, segment)
|
||||
segment = self.driver.allocate_tenant_segment(self.session)
|
||||
self.assertThat(segment[api.SEGMENTATION_ID],
|
||||
matchers.GreaterThan(TUN_MIN - 1))
|
||||
self.assertThat(segment[api.SEGMENTATION_ID],
|
||||
matchers.LessThan(TUN_MAX + 1))
|
||||
tunnel_ids.add(segment[api.SEGMENTATION_ID])
|
||||
|
||||
for tunnel_id in tunnel_ids:
|
||||
segment[api.SEGMENTATION_ID] = tunnel_id
|
||||
self.driver.release_segment(self.session, segment)
|
||||
|
||||
def test_vxlan_endpoints(self):
|
||||
"""Test VXLAN allocation/de-allocation."""
|
||||
|
||||
# Set first endpoint, verify it gets VXLAN VNI 1
|
||||
vxlan1_endpoint = self.driver.add_endpoint(TUNNEL_IP_ONE,
|
||||
VXLAN_UDP_PORT_ONE)
|
||||
self.assertEqual(TUNNEL_IP_ONE, vxlan1_endpoint.ip_address)
|
||||
self.assertEqual(VXLAN_UDP_PORT_ONE, vxlan1_endpoint.udp_port)
|
||||
|
||||
# Set second endpoint, verify it gets VXLAN VNI 2
|
||||
vxlan2_endpoint = self.driver.add_endpoint(TUNNEL_IP_TWO,
|
||||
VXLAN_UDP_PORT_TWO)
|
||||
self.assertEqual(TUNNEL_IP_TWO, vxlan2_endpoint.ip_address)
|
||||
self.assertEqual(VXLAN_UDP_PORT_TWO, vxlan2_endpoint.udp_port)
|
||||
|
||||
# Get all the endpoints
|
||||
endpoints = self.driver.get_endpoints()
|
||||
for endpoint in endpoints:
|
||||
if endpoint['ip_address'] == TUNNEL_IP_ONE:
|
||||
self.assertEqual(VXLAN_UDP_PORT_ONE, endpoint['udp_port'])
|
||||
elif endpoint['ip_address'] == TUNNEL_IP_TWO:
|
||||
self.assertEqual(VXLAN_UDP_PORT_TWO, endpoint['udp_port'])
|
@ -110,6 +110,7 @@ neutron.ml2.type_drivers =
|
||||
local = neutron.plugins.ml2.drivers.type_local:LocalTypeDriver
|
||||
vlan = neutron.plugins.ml2.drivers.type_vlan:VlanTypeDriver
|
||||
gre = neutron.plugins.ml2.drivers.type_gre:GreTypeDriver
|
||||
vxlan = neutron.plugins.ml2.drivers.type_vxlan:VxlanTypeDriver
|
||||
neutron.ml2.mechanism_drivers =
|
||||
logger = neutron.tests.unit.ml2.drivers.mechanism_logger:LoggerMechanismDriver
|
||||
test = neutron.tests.unit.ml2.drivers.mechanism_test:TestMechanismDriver
|
||||
|
Loading…
Reference in New Issue
Block a user