ML2 will check the config parameters for the MTU settings.
It will check the segment, path and physnet mtu settings.
Change-Id: I58b57e01ec9bcafd7cdcfbf03149e98c3a1291ed
Partially-Implements: blueprint mtu-selection-and-advertisement
# Values for network_type
VXLAN_UDP_PORT = 4789
+
+# Network Type MTU overhead
+GRE_ENCAP_OVERHEAD = 42
+VXLAN_ENCAP_OVERHEAD = 50
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
"""
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):
# 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")
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__)
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
"""
def __init__(self):
+ super(FlatTypeDriver, self).__init__()
self._parse_networks(cfg.CONF.ml2_type_flat.flat_networks)
def _parse_networks(self, entries):
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):
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
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
def release_segment(self, session, segment):
# No resources to release
pass
+
+ def get_mtu(self, physical_network=None):
+ pass
# under the License.
import abc
+from oslo_config import cfg
from oslo_log import log
from neutron.common import exceptions as exc
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
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)
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]
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):
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
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)
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]
"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
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
"""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:
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]
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,
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']
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(
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'))
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
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):
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'
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,
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)
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
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):