Merge "Add MTU selection to ML2"

This commit is contained in:
Jenkins 2015-03-17 22:17:54 +00:00 committed by Gerrit Code Review
commit e26532874a
15 changed files with 201 additions and 14 deletions

View File

@ -85,3 +85,7 @@ TYPE_NONE = 'none'
# Values for network_type
VXLAN_UDP_PORT = 4789
# Network Type MTU overhead
GRE_ENCAP_OVERHEAD = 42
VXLAN_ENCAP_OVERHEAD = 50

View File

@ -25,6 +25,7 @@ ID = 'id'
NETWORK_TYPE = 'network_type'
PHYSICAL_NETWORK = 'physical_network'
SEGMENTATION_ID = 'segmentation_id'
MTU = 'mtu'
# The following keys are used in the binding level dictionaries
# available via the binding_levels and original_binding_levels
@ -142,6 +143,17 @@ class TypeDriver(object):
"""
pass
@abc.abstractmethod
def get_mtu(self, physical):
"""Get driver's network MTU.
:returns mtu: maximum transmission unit
Returns the mtu for the network based on the config values and
the network type.
"""
pass
@six.add_metaclass(abc.ABCMeta)
class NetworkContext(object):

View File

@ -13,24 +13,42 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from oslo_db import exception as db_exc
from oslo_log import log
from neutron.common import exceptions as exc
from neutron.common import utils
from neutron.plugins.ml2 import driver_api as api
LOG = log.getLogger(__name__)
class TypeDriverHelper(api.TypeDriver):
"""TypeDriver Helper for segment allocation.
class BaseTypeDriver(api.TypeDriver):
"""BaseTypeDriver for functions common to Segment and flat."""
def __init__(self):
try:
self.physnet_mtus = utils.parse_mappings(
cfg.CONF.ml2.physical_network_mtus
)
except Exception:
self.physnet_mtus = []
def get_mtu(self, physical_network=None):
return cfg.CONF.ml2.segment_mtu
class SegmentTypeDriver(BaseTypeDriver):
"""SegmentTypeDriver for segment allocation.
Provide methods helping to perform segment allocation fully or partially
specified.
"""
def __init__(self, model):
super(SegmentTypeDriver, self).__init__()
self.model = model
self.primary_keys = set(dict(model.__table__.columns))
self.primary_keys.remove("allocated")

View File

@ -23,6 +23,7 @@ from neutron.db import model_base
from neutron.i18n import _LI, _LW
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
LOG = log.getLogger(__name__)
@ -50,7 +51,7 @@ class FlatAllocation(model_base.BASEV2):
primary_key=True)
class FlatTypeDriver(api.TypeDriver):
class FlatTypeDriver(helpers.BaseTypeDriver):
"""Manage state for flat networks with ML2.
The FlatTypeDriver implements the 'flat' network_type. Flat
@ -62,6 +63,7 @@ class FlatTypeDriver(api.TypeDriver):
"""
def __init__(self):
super(FlatTypeDriver, self).__init__()
self._parse_networks(cfg.CONF.ml2_type_flat.flat_networks)
def _parse_networks(self, entries):
@ -112,6 +114,7 @@ class FlatTypeDriver(api.TypeDriver):
except db_exc.DBDuplicateEntry:
raise exc.FlatNetworkInUse(
physical_network=physical_network)
segment[api.MTU] = self.get_mtu(alloc.physical_network)
return segment
def allocate_tenant_segment(self, session):
@ -130,3 +133,12 @@ class FlatTypeDriver(api.TypeDriver):
else:
LOG.warning(_LW("No flat network found on physical network %s"),
physical_network)
def get_mtu(self, physical_network):
seg_mtu = super(FlatTypeDriver, self).get_mtu()
mtu = []
if seg_mtu > 0:
mtu.append(seg_mtu)
if physical_network in self.physnet_mtus:
mtu.append(int(self.physnet_mtus[physical_network]))
return min(mtu) if mtu else 0

View File

@ -166,3 +166,7 @@ class GreTypeDriver(type_tunnel.TunnelTypeDriver):
with session.begin(subtransactions=True):
session.query(GreEndpoints).filter_by(ip_address=ip).delete()
def get_mtu(self, physical_network=None):
mtu = super(GreTypeDriver, self).get_mtu(physical_network)
return mtu - p_const.GRE_ENCAP_OVERHEAD if mtu else 0

View File

@ -62,3 +62,6 @@ class LocalTypeDriver(api.TypeDriver):
def release_segment(self, session, segment):
# No resources to release
pass
def get_mtu(self, physical_network=None):
pass

View File

@ -14,6 +14,7 @@
# under the License.
import abc
from oslo_config import cfg
from oslo_log import log
from neutron.common import exceptions as exc
@ -28,7 +29,7 @@ LOG = log.getLogger(__name__)
TUNNEL = 'tunnel'
class TunnelTypeDriver(helpers.TypeDriverHelper):
class TunnelTypeDriver(helpers.SegmentTypeDriver):
"""Define stable abstract interface for ML2 type drivers.
tunnel type networks rely on tunnel endpoints. This class defines abstract
@ -145,7 +146,8 @@ class TunnelTypeDriver(helpers.TypeDriverHelper):
raise exc.TunnelIdInUse(tunnel_id=segmentation_id)
return {api.NETWORK_TYPE: self.get_type(),
api.PHYSICAL_NETWORK: None,
api.SEGMENTATION_ID: getattr(alloc, self.segmentation_key)}
api.SEGMENTATION_ID: getattr(alloc, self.segmentation_key),
api.MTU: self.get_mtu()}
def allocate_tenant_segment(self, session):
alloc = self.allocate_partially_specified_segment(session)
@ -153,7 +155,8 @@ class TunnelTypeDriver(helpers.TypeDriverHelper):
return
return {api.NETWORK_TYPE: self.get_type(),
api.PHYSICAL_NETWORK: None,
api.SEGMENTATION_ID: getattr(alloc, self.segmentation_key)}
api.SEGMENTATION_ID: getattr(alloc, self.segmentation_key),
api.MTU: self.get_mtu()}
def release_segment(self, session, segment):
tunnel_id = segment[api.SEGMENTATION_ID]
@ -183,6 +186,15 @@ class TunnelTypeDriver(helpers.TypeDriverHelper):
filter_by(**{self.segmentation_key: tunnel_id}).
first())
def get_mtu(self, physical_network=None):
seg_mtu = super(TunnelTypeDriver, self).get_mtu()
mtu = []
if seg_mtu > 0:
mtu.append(seg_mtu)
if cfg.CONF.ml2.path_mtu > 0:
mtu.append(cfg.CONF.ml2.path_mtu)
return min(mtu) if mtu else 0
class TunnelRpcCallbackMixin(object):

View File

@ -73,7 +73,7 @@ class VlanAllocation(model_base.BASEV2):
allocated = sa.Column(sa.Boolean, nullable=False)
class VlanTypeDriver(helpers.TypeDriverHelper):
class VlanTypeDriver(helpers.SegmentTypeDriver):
"""Manage state for VLAN networks with ML2.
The VlanTypeDriver implements the 'vlan' network_type. VLAN
@ -217,7 +217,8 @@ class VlanTypeDriver(helpers.TypeDriverHelper):
return {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: alloc.physical_network,
api.SEGMENTATION_ID: alloc.vlan_id}
api.SEGMENTATION_ID: alloc.vlan_id,
api.MTU: self.get_mtu(alloc.physical_network)}
def allocate_tenant_segment(self, session):
alloc = self.allocate_partially_specified_segment(session)
@ -225,7 +226,8 @@ class VlanTypeDriver(helpers.TypeDriverHelper):
return
return {api.NETWORK_TYPE: p_const.TYPE_VLAN,
api.PHYSICAL_NETWORK: alloc.physical_network,
api.SEGMENTATION_ID: alloc.vlan_id}
api.SEGMENTATION_ID: alloc.vlan_id,
api.MTU: self.get_mtu(alloc.physical_network)}
def release_segment(self, session, segment):
physical_network = segment[api.PHYSICAL_NETWORK]
@ -258,3 +260,12 @@ class VlanTypeDriver(helpers.TypeDriverHelper):
"network %(physical_network)s"),
{'vlan_id': vlan_id,
'physical_network': physical_network})
def get_mtu(self, physical_network):
seg_mtu = super(VlanTypeDriver, self).get_mtu()
mtu = []
if seg_mtu > 0:
mtu.append(seg_mtu)
if physical_network in self.physnet_mtus:
mtu.append(int(self.physnet_mtus[physical_network]))
return min(mtu) if mtu else 0

View File

@ -177,3 +177,7 @@ class VxlanTypeDriver(type_tunnel.TunnelTypeDriver):
with session.begin(subtransactions=True):
session.query(VxlanEndpoints).filter_by(ip_address=ip).delete()
def get_mtu(self, physical_network=None):
mtu = super(VxlanTypeDriver, self).get_mtu()
return mtu - p_const.VXLAN_ENCAP_OVERHEAD if mtu else 0

View File

@ -165,6 +165,7 @@ class TypeManager(stevedore.named.NamedExtensionManager):
"""Call type drivers to create network segments."""
segments = self._process_provider_create(network)
session = context.session
mtu = []
with session.begin(subtransactions=True):
network_id = network['id']
if segments:
@ -173,9 +174,14 @@ class TypeManager(stevedore.named.NamedExtensionManager):
session, segment)
db.add_network_segment(session, network_id,
segment, segment_index)
if segment.get(api.MTU) > 0:
mtu.append(segment[api.MTU])
else:
segment = self.allocate_tenant_segment(session)
db.add_network_segment(session, network_id, segment)
if segment.get(api.MTU) > 0:
mtu.append(segment[api.MTU])
network[api.MTU] = min(mtu) if mtu else 0
def is_partial_segment(self, segment):
network_type = segment[api.NETWORK_TYPE]

View File

@ -585,6 +585,12 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
mech_context = driver_context.NetworkContext(self, context,
result)
self.mechanism_manager.create_network_precommit(mech_context)
if net_data.get(api.MTU, 0) > 0:
res = super(Ml2Plugin, self).update_network(context,
result['id'], network)
result[api.MTU] = res.get(api.MTU, 0)
return result, mech_context
@oslo_db_api.wrap_db_retry(max_retries=db_api.MAX_RETRIES,

View File

@ -16,10 +16,10 @@
from neutron.common import exceptions as exc
import neutron.db.api as db
from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2 import config
from neutron.plugins.ml2 import driver_api as api
from neutron.plugins.ml2.drivers import type_flat
from neutron.tests.unit import testlib_api
from oslo_config import cfg
FLAT_NETWORKS = ['flat_net1', 'flat_net2']
@ -29,10 +29,11 @@ class FlatTypeTest(testlib_api.SqlTestCase):
def setUp(self):
super(FlatTypeTest, self).setUp()
cfg.CONF.set_override('flat_networks', FLAT_NETWORKS,
config.cfg.CONF.set_override('flat_networks', FLAT_NETWORKS,
group='ml2_type_flat')
self.driver = type_flat.FlatTypeDriver()
self.session = db.get_session()
self.driver.physnet_mtus = []
def _get_allocation(self, session, segment):
return session.query(type_flat.FlatAllocation).filter_by(
@ -111,3 +112,24 @@ class FlatTypeTest(testlib_api.SqlTestCase):
def test_allocate_tenant_segment(self):
observed = self.driver.allocate_tenant_segment(self.session)
self.assertIsNone(observed)
def test_get_mtu(self):
config.cfg.CONF.set_override('segment_mtu', 1475, group='ml2')
config.cfg.CONF.set_override('path_mtu', 1400, group='ml2')
self.driver.physnet_mtus = {'physnet1': 1450, 'physnet2': 1400}
self.assertEqual(1450, self.driver.get_mtu('physnet1'))
config.cfg.CONF.set_override('segment_mtu', 1375, group='ml2')
config.cfg.CONF.set_override('path_mtu', 1400, group='ml2')
self.driver.physnet_mtus = {'physnet1': 1450, 'physnet2': 1400}
self.assertEqual(1375, self.driver.get_mtu('physnet1'))
config.cfg.CONF.set_override('segment_mtu', 0, group='ml2')
config.cfg.CONF.set_override('path_mtu', 1425, group='ml2')
self.driver.physnet_mtus = {'physnet1': 1450, 'physnet2': 1400}
self.assertEqual(1400, self.driver.get_mtu('physnet2'))
config.cfg.CONF.set_override('segment_mtu', 0, group='ml2')
config.cfg.CONF.set_override('path_mtu', 0, group='ml2')
self.driver.physnet_mtus = {}
self.assertEqual(0, self.driver.get_mtu('physnet1'))

View File

@ -21,6 +21,7 @@ import testtools
from neutron.db import api as db_api
from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2 import config
from neutron.plugins.ml2.drivers import type_gre
from neutron.tests.unit.ml2 import test_rpcapi
from neutron.tests.unit.ml2 import test_type_tunnel
@ -125,6 +126,30 @@ class GreTypeTest(test_type_tunnel.TunnelTypeTestMixin,
with testtools.ExpectedException(sa_exc.NoResultFound):
_get_allocation(session, 1)
def test_get_mtu(self):
config.cfg.CONF.set_override('segment_mtu', 1500, group='ml2')
config.cfg.CONF.set_override('path_mtu', 1475, group='ml2')
self.driver.physnet_mtus = {'physnet1': 1450, 'physnet2': 1400}
self.assertEqual(1475 - p_const.GRE_ENCAP_OVERHEAD,
self.driver.get_mtu('physnet1'))
config.cfg.CONF.set_override('segment_mtu', 1425, group='ml2')
config.cfg.CONF.set_override('path_mtu', 1475, group='ml2')
self.driver.physnet_mtus = {'physnet1': 1400, 'physnet2': 1400}
self.assertEqual(1425 - p_const.GRE_ENCAP_OVERHEAD,
self.driver.get_mtu('physnet1'))
config.cfg.CONF.set_override('segment_mtu', 0, group='ml2')
config.cfg.CONF.set_override('path_mtu', 1475, group='ml2')
self.driver.physnet_mtus = {'physnet1': 1450, 'physnet2': 1425}
self.assertEqual(1475 - p_const.GRE_ENCAP_OVERHEAD,
self.driver.get_mtu('physnet2'))
config.cfg.CONF.set_override('segment_mtu', 0, group='ml2')
config.cfg.CONF.set_override('path_mtu', 0, group='ml2')
self.driver.physnet_mtus = {}
self.assertEqual(0, self.driver.get_mtu('physnet1'))
class GreTypeMultiRangeTest(test_type_tunnel.TunnelTypeMultiRangeTestMixin,
testlib_api.SqlTestCase):

View File

@ -20,10 +20,10 @@ from neutron.common import exceptions as exc
import neutron.db.api as db
from neutron.plugins.common import constants as p_const
from neutron.plugins.common import utils as plugin_utils
from neutron.plugins.ml2 import config
from neutron.plugins.ml2 import driver_api as api
from neutron.plugins.ml2.drivers import type_vlan
from neutron.tests.unit import testlib_api
from oslo_config import cfg
PROVIDER_NET = 'phys_net1'
TENANT_NET = 'phys_net2'
@ -41,13 +41,15 @@ class VlanTypeTest(testlib_api.SqlTestCase):
def setUp(self):
super(VlanTypeTest, self).setUp()
cfg.CONF.set_override('network_vlan_ranges', NETWORK_VLAN_RANGES,
group='ml2_type_vlan')
config.cfg.CONF.set_override('network_vlan_ranges',
NETWORK_VLAN_RANGES,
group='ml2_type_vlan')
self.network_vlan_ranges = plugin_utils.parse_network_vlan_ranges(
NETWORK_VLAN_RANGES)
self.driver = type_vlan.VlanTypeDriver()
self.driver._sync_vlan_allocations()
self.session = db.get_session()
self.driver.physnet_mtus = []
def test_parse_network_exception_handling(self):
with mock.patch.object(plugin_utils,
@ -202,6 +204,27 @@ class VlanTypeTest(testlib_api.SqlTestCase):
self.session,
segment)
def test_get_mtu(self):
config.cfg.CONF.set_override('segment_mtu', 1475, group='ml2')
config.cfg.CONF.set_override('path_mtu', 1400, group='ml2')
self.driver.physnet_mtus = {'physnet1': 1450, 'physnet2': 1400}
self.assertEqual(1450, self.driver.get_mtu('physnet1'))
config.cfg.CONF.set_override('segment_mtu', 1375, group='ml2')
config.cfg.CONF.set_override('path_mtu', 1400, group='ml2')
self.driver.physnet_mtus = {'physnet1': 1450, 'physnet2': 1400}
self.assertEqual(1375, self.driver.get_mtu('physnet1'))
config.cfg.CONF.set_override('segment_mtu', 0, group='ml2')
config.cfg.CONF.set_override('path_mtu', 1400, group='ml2')
self.driver.physnet_mtus = {'physnet1': 1450, 'physnet2': 1400}
self.assertEqual(1450, self.driver.get_mtu('physnet1'))
config.cfg.CONF.set_override('segment_mtu', 0, group='ml2')
config.cfg.CONF.set_override('path_mtu', 0, group='ml2')
self.driver.physnet_mtus = {}
self.assertEqual(0, self.driver.get_mtu('physnet1'))
def test_allocate_tenant_segment(self):
for __ in range(VLAN_MIN, VLAN_MAX + 1):
segment = self.driver.allocate_tenant_segment(self.session)

View File

@ -16,6 +16,7 @@
import mock
from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2 import config
from neutron.plugins.ml2.drivers import type_vxlan
from neutron.tests.unit.ml2 import test_rpcapi
from neutron.tests.unit.ml2 import test_type_tunnel
@ -93,6 +94,30 @@ class VxlanTypeTest(test_type_tunnel.TunnelTypeTestMixin,
endpoints = self.driver.get_endpoints()
self.assertNotIn(TUNNEL_IP_ONE, endpoints)
def test_get_mtu(self):
config.cfg.CONF.set_override('segment_mtu', 1500, group='ml2')
config.cfg.CONF.set_override('path_mtu', 1475, group='ml2')
self.driver.physnet_mtus = {'physnet1': 1450, 'physnet2': 1400}
self.assertEqual(1475 - p_const.VXLAN_ENCAP_OVERHEAD,
self.driver.get_mtu('physnet1'))
config.cfg.CONF.set_override('segment_mtu', 1450, group='ml2')
config.cfg.CONF.set_override('path_mtu', 1475, group='ml2')
self.driver.physnet_mtus = {'physnet1': 1400, 'physnet2': 1425}
self.assertEqual(1450 - p_const.VXLAN_ENCAP_OVERHEAD,
self.driver.get_mtu('physnet1'))
config.cfg.CONF.set_override('segment_mtu', 0, group='ml2')
config.cfg.CONF.set_override('path_mtu', 1450, group='ml2')
self.driver.physnet_mtus = {'physnet1': 1425, 'physnet2': 1400}
self.assertEqual(1450 - p_const.VXLAN_ENCAP_OVERHEAD,
self.driver.get_mtu('physnet1'))
config.cfg.CONF.set_override('segment_mtu', 0, group='ml2')
config.cfg.CONF.set_override('path_mtu', 0, group='ml2')
self.driver.physnet_mtus = {}
self.assertEqual(0, self.driver.get_mtu('physnet1'))
class VxlanTypeMultiRangeTest(test_type_tunnel.TunnelTypeMultiRangeTestMixin,
testlib_api.SqlTestCase):