from neutron.openstack.common import log
from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2 import driver_api as api
+from neutron.plugins.ml2.drivers import helpers
from neutron.plugins.ml2.drivers import type_tunnel
LOG = log.getLogger(__name__)
return "<GreTunnelEndpoint(%s)>" % self.ip_address
-class GreTypeDriver(type_tunnel.TunnelTypeDriver):
+class GreTypeDriver(helpers.TypeDriverHelper, type_tunnel.TunnelTypeDriver):
+
+ def __init__(self):
+ super(GreTypeDriver, self).__init__(GreAllocation)
def get_type(self):
return p_const.TYPE_GRE
self._sync_gre_allocations()
def reserve_provider_segment(self, session, segment):
- segmentation_id = segment.get(api.SEGMENTATION_ID)
- with session.begin(subtransactions=True):
- try:
- alloc = (session.query(GreAllocation).
- filter_by(gre_id=segmentation_id).
- with_lockmode('update').
- one())
- if alloc.allocated:
- raise exc.TunnelIdInUse(tunnel_id=segmentation_id)
- LOG.debug(_("Reserving specific gre tunnel %s from pool"),
- segmentation_id)
- alloc.allocated = True
- except sa_exc.NoResultFound:
- LOG.debug(_("Reserving specific gre tunnel %s outside pool"),
- segmentation_id)
- alloc = GreAllocation(gre_id=segmentation_id)
- alloc.allocated = True
- session.add(alloc)
- return segment
+ if self.is_partial_segment(segment):
+ alloc = self.allocate_partially_specified_segment(session)
+ if not alloc:
+ raise exc.NoNetworkAvailable
+ else:
+ segmentation_id = segment.get(api.SEGMENTATION_ID)
+ alloc = self.allocate_fully_specified_segment(
+ session, gre_id=segmentation_id)
+ if not alloc:
+ raise exc.TunnelIdInUse(tunnel_id=segmentation_id)
+ return {api.NETWORK_TYPE: p_const.TYPE_GRE,
+ api.PHYSICAL_NETWORK: None,
+ api.SEGMENTATION_ID: alloc.gre_id}
def allocate_tenant_segment(self, session):
- with session.begin(subtransactions=True):
- alloc = (session.query(GreAllocation).
- filter_by(allocated=False).
- with_lockmode('update').
- first())
- if alloc:
- LOG.debug(_("Allocating gre tunnel id %(gre_id)s"),
- {'gre_id': alloc.gre_id})
- alloc.allocated = True
- return {api.NETWORK_TYPE: p_const.TYPE_GRE,
- api.PHYSICAL_NETWORK: None,
- api.SEGMENTATION_ID: alloc.gre_id}
+ alloc = self.allocate_partially_specified_segment(session)
+ if not alloc:
+ return
+ return {api.NETWORK_TYPE: p_const.TYPE_GRE,
+ api.PHYSICAL_NETWORK: None,
+ api.SEGMENTATION_ID: alloc.gre_id}
def release_segment(self, session, segment):
gre_id = segment[api.SEGMENTATION_ID]
LOG.info(_("%(type)s ID ranges: %(range)s"),
{'type': tunnel_type, 'range': current_range})
+ def is_partial_segment(self, segment):
+ return segment.get(api.SEGMENTATION_ID) is None
+
def validate_provider_segment(self, segment):
physical_network = segment.get(api.PHYSICAL_NETWORK)
if physical_network:
"network") % segment.get(api.NETWORK_TYPE)
raise exc.InvalidInput(error_message=msg)
- segmentation_id = segment.get(api.SEGMENTATION_ID)
- if not segmentation_id:
- msg = _("segmentation_id required for %s provider "
- "network") % segment.get(api.NETWORK_TYPE)
- raise exc.InvalidInput(error_message=msg)
-
for key, value in segment.items():
if value and key not in [api.NETWORK_TYPE,
api.SEGMENTATION_ID]:
from neutron.openstack.common import log
from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2 import driver_api as api
+from neutron.plugins.ml2.drivers import helpers
from neutron.plugins.ml2.drivers import type_tunnel
LOG = log.getLogger(__name__)
return "<VxlanTunnelEndpoint(%s)>" % self.ip_address
-class VxlanTypeDriver(type_tunnel.TunnelTypeDriver):
+class VxlanTypeDriver(helpers.TypeDriverHelper, type_tunnel.TunnelTypeDriver):
+
+ def __init__(self):
+ super(VxlanTypeDriver, self).__init__(VxlanAllocation)
def get_type(self):
return p_const.TYPE_VXLAN
self._sync_vxlan_allocations()
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)
- return segment
+ if self.is_partial_segment(segment):
+ alloc = self.allocate_partially_specified_segment(session)
+ if not alloc:
+ raise exc.NoNetworkAvailable
+ else:
+ segmentation_id = segment.get(api.SEGMENTATION_ID)
+ alloc = self.allocate_fully_specified_segment(
+ session, vxlan_vni=segmentation_id)
+ if not alloc:
+ raise exc.TunnelIdInUse(tunnel_id=segmentation_id)
+ return {api.NETWORK_TYPE: p_const.TYPE_VXLAN,
+ api.PHYSICAL_NETWORK: None,
+ api.SEGMENTATION_ID: alloc.vxlan_vni}
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: p_const.TYPE_VXLAN,
- api.PHYSICAL_NETWORK: None,
- api.SEGMENTATION_ID: alloc.vxlan_vni}
+ alloc = self.allocate_partially_specified_segment(session)
+ if not alloc:
+ return
+ return {api.NETWORK_TYPE: p_const.TYPE_VXLAN,
+ api.PHYSICAL_NETWORK: None,
+ api.SEGMENTATION_ID: alloc.vxlan_vni}
def release_segment(self, session, segment):
vxlan_vni = segment[api.SEGMENTATION_ID]
self.driver.validate_provider_segment(segment)
segment[api.PHYSICAL_NETWORK] = None
- with testtools.ExpectedException(exc.InvalidInput):
- self.driver.validate_provider_segment(segment)
+ self.driver.validate_provider_segment(segment)
+
+ segment[api.SEGMENTATION_ID] = 1
+ self.driver.validate_provider_segment(segment)
def test_sync_tunnel_allocations(self):
self.assertIsNone(
(TUN_MAX + 5 + 1))
)
- def test_reserve_provider_segment(self):
+ def test_partial_segment_is_partial_segment(self):
segment = {api.NETWORK_TYPE: 'gre',
- api.PHYSICAL_NETWORK: 'None',
+ api.PHYSICAL_NETWORK: None,
+ api.SEGMENTATION_ID: None}
+ self.assertTrue(self.driver.is_partial_segment(segment))
+
+ def test_specific_segment_is_not_partial_segment(self):
+ segment = {api.NETWORK_TYPE: 'gre',
+ api.PHYSICAL_NETWORK: None,
+ api.SEGMENTATION_ID: 101}
+ self.assertFalse(self.driver.is_partial_segment(segment))
+
+ def test_reserve_provider_segment_full_specs(self):
+ segment = {api.NETWORK_TYPE: 'gre',
+ api.PHYSICAL_NETWORK: None,
api.SEGMENTATION_ID: 101}
observed = self.driver.reserve_provider_segment(self.session, segment)
alloc = self.driver.get_gre_allocation(self.session,
observed[api.SEGMENTATION_ID])
self.assertIsNone(alloc)
+ def test_reserve_provider_segment(self):
+ tunnel_ids = set()
+ specs = {api.NETWORK_TYPE: 'gre',
+ api.PHYSICAL_NETWORK: 'None',
+ api.SEGMENTATION_ID: None}
+
+ for x in xrange(TUN_MIN, TUN_MAX + 1):
+ segment = self.driver.reserve_provider_segment(self.session,
+ specs)
+ self.assertEqual('gre', segment[api.NETWORK_TYPE])
+ 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])
+
+ with testtools.ExpectedException(exc.NoNetworkAvailable):
+ segment = self.driver.reserve_provider_segment(self.session,
+ specs)
+
+ segment = {api.NETWORK_TYPE: 'gre',
+ api.PHYSICAL_NETWORK: 'None',
+ api.SEGMENTATION_ID: tunnel_ids.pop()}
+ self.driver.release_segment(self.session, segment)
+ segment = self.driver.reserve_provider_segment(self.session, specs)
+ 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_allocate_tenant_segment(self):
tunnel_ids = set()
for x in moves.xrange(TUN_MIN, TUN_MAX + 1):
self.driver.validate_provider_segment(segment)
segment[api.PHYSICAL_NETWORK] = None
- with testtools.ExpectedException(exc.InvalidInput):
- self.driver.validate_provider_segment(segment)
+ self.driver.validate_provider_segment(segment)
+
+ segment[api.SEGMENTATION_ID] = 1
+ self.driver.validate_provider_segment(segment)
def test_sync_tunnel_allocations(self):
self.assertIsNone(
get_vxlan_allocation(self.session,
(TUN_MAX + 5 + 1)))
- def test_reserve_provider_segment(self):
+ def test_partial_segment_is_partial_segment(self):
segment = {api.NETWORK_TYPE: 'vxlan',
- api.PHYSICAL_NETWORK: 'None',
+ api.PHYSICAL_NETWORK: None,
+ api.SEGMENTATION_ID: None}
+ self.assertTrue(self.driver.is_partial_segment(segment))
+
+ def test_specific_segment_is_not_partial_segment(self):
+ segment = {api.NETWORK_TYPE: 'vxlan',
+ api.PHYSICAL_NETWORK: None,
+ api.SEGMENTATION_ID: 101}
+ self.assertFalse(self.driver.is_partial_segment(segment))
+
+ def test_reserve_provider_segment_full_specs(self):
+ segment = {api.NETWORK_TYPE: 'vxlan',
+ api.PHYSICAL_NETWORK: None,
api.SEGMENTATION_ID: 101}
observed = self.driver.reserve_provider_segment(self.session, segment)
alloc = self.driver.get_vxlan_allocation(self.session,
observed[api.SEGMENTATION_ID])
self.assertIsNone(alloc)
+ def test_reserve_provider_segment(self):
+ tunnel_ids = set()
+ specs = {api.NETWORK_TYPE: 'vxlan',
+ api.PHYSICAL_NETWORK: 'None',
+ api.SEGMENTATION_ID: None}
+
+ for x in xrange(TUN_MIN, TUN_MAX + 1):
+ segment = self.driver.reserve_provider_segment(self.session,
+ specs)
+ self.assertEqual('vxlan', segment[api.NETWORK_TYPE])
+ 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])
+
+ with testtools.ExpectedException(exc.NoNetworkAvailable):
+ segment = self.driver.reserve_provider_segment(self.session,
+ specs)
+
+ 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.reserve_provider_segment(self.session, specs)
+ 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_allocate_tenant_segment(self):
tunnel_ids = set()
for x in moves.xrange(TUN_MIN, TUN_MAX + 1):