Merge "[Linuxbridge] Handle properly too big VXLAN MTU values"

This commit is contained in:
Zuul 2018-04-30 21:25:13 +00:00 committed by Gerrit Code Review
commit 0e27778b06
4 changed files with 48 additions and 24 deletions

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import errno
import os
import re
import time
@ -25,6 +26,7 @@ from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
from pyroute2.netlink.rtnl import ifinfmsg
from pyroute2 import NetlinkError
from pyroute2 import netns
import six
@ -65,6 +67,11 @@ class AddressNotReady(exceptions.NeutronException):
"become ready: %(reason)s")
class InvalidArgument(exceptions.NeutronException):
message = _("Invalid value %(value)s for parameter %(parameter)s "
"provided.")
class SubProcessBase(object):
def __init__(self, namespace=None,
log_fail_as_error=True):
@ -508,8 +515,13 @@ class IpLinkCommand(IpDeviceCommandBase):
self.name, self._parent.namespace, ifinfmsg.IFF_ALLMULTI)
def set_mtu(self, mtu_size):
privileged.set_link_attribute(
self.name, self._parent.namespace, mtu=mtu_size)
try:
privileged.set_link_attribute(
self.name, self._parent.namespace, mtu=mtu_size)
except NetlinkError as e:
if e.code == errno.EINVAL:
raise InvalidArgument(parameter="MTU", value=mtu_size)
raise
def set_up(self):
privileged.set_link_attribute(

View File

@ -347,25 +347,8 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase):
args['proxy'] = cfg.CONF.VXLAN.arp_responder
try:
if mtu:
phys_dev_mtu = ip_lib.get_device_mtu(self.local_int)
max_mtu = phys_dev_mtu - constants.VXLAN_ENCAP_OVERHEAD
if mtu > max_mtu:
LOG.error("Provided MTU value %(mtu)s for VNI "
"%(segmentation_id)s is too high. "
"According to physical device %(dev)s "
"MTU=%(phys_mtu)s maximum available "
"MTU is %(max_mtu)s",
{'mtu': mtu,
'segmentation_id': segmentation_id,
'dev': self.local_int,
'phys_mtu': phys_dev_mtu,
'max_mtu': max_mtu})
return None
int_vxlan = self.ip.add_vxlan(interface, segmentation_id,
**args)
if mtu:
int_vxlan.link.set_mtu(mtu)
except RuntimeError:
with excutils.save_and_reraise_exception() as ctxt:
# perform this check after an attempt rather than before
@ -376,6 +359,20 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase):
"VNI %s because it is in use by another "
"interface.", segmentation_id)
return None
if mtu:
try:
int_vxlan.link.set_mtu(mtu)
except ip_lib.InvalidArgument:
phys_dev_mtu = ip_lib.get_device_mtu(self.local_int)
LOG.error("Provided MTU value %(mtu)s for VNI "
"%(segmentation_id)s is too high according "
"to physical device %(dev)s MTU=%(phys_mtu)s.",
{'mtu': mtu,
'segmentation_id': segmentation_id,
'dev': self.local_int,
'phys_mtu': phys_dev_mtu})
int_vxlan.link.delete()
return None
int_vxlan.disable_ipv6()
int_vxlan.link.set_up()
LOG.debug("Done creating vxlan interface %s", interface)

View File

@ -480,6 +480,10 @@ class IpLibTestCase(IpLibTestFramework):
self.assertEqual(1450, device.link.mtu)
# Check if proper exception will be raised when wrong MTU value is
# provided
self.assertRaises(ip_lib.InvalidArgument, device.link.set_mtu, 1)
def test_set_link_allmulticast_on(self):
attr = self.generate_device_details()
device = self.manage_device(attr)

View File

@ -442,22 +442,33 @@ class TestLinuxBridgeManager(base.BaseTestCase):
def test_ensure_vxlan_mtu_too_big(self):
seg_id = "12345678"
physical_mtu = 1500
# Any mtu value which will be higher than physical_mtu - 50 should
# be too big
# Any mtu value which will be higher than
# physical_mtu - VXLAN_ENCAP_OVERHEAD should raise NetlinkError
mtu = 1490
self.lbm.local_int = 'eth0'
self.lbm.vxlan_mode = lconst.VXLAN_MCAST
with mock.patch.object(ip_lib, 'device_exists', return_value=False):
vxlan_dev = FakeIpDevice()
vxlan_dev = mock.Mock()
with mock.patch.object(vxlan_dev, 'disable_ipv6') as dv6_fn,\
mock.patch.object(self.lbm.ip, 'add_vxlan',
return_value=vxlan_dev) as add_vxlan_fn,\
mock.patch.object(
vxlan_dev.link, 'set_mtu',
side_effect=ip_lib.InvalidArgument(
parameter="MTU", value=mtu)),\
mock.patch.object(ip_lib, 'get_device_mtu',
return_value=physical_mtu):
return_value=physical_mtu),\
mock.patch.object(vxlan_dev.link, 'delete') as delete_dev:
self.assertFalse(
self.lbm.ensure_vxlan(seg_id, mtu=mtu))
add_vxlan_fn.assert_not_called()
add_vxlan_fn.assert_called_with("vxlan-" + seg_id, seg_id,
group="224.0.0.1",
srcport=(0, 0),
dstport=None,
ttl=None,
dev=self.lbm.local_int)
delete_dev.assert_called_once_with()
dv6_fn.assert_not_called()
def test__update_interface_ip_details(self):