[Linuxbridge] Handle properly too big VXLAN MTU values
In case when MTU value configured for VXLAN network is higher than physical device's MTU - VXLAN overhead then Linuxbridge agent will not be able to create properly vxlan interface with desired MTU value. In patch [1] there was introduced validation if MTU of physical device is big enough to create MTU with required MTU value but it was working only for IPv4 tunnels as for IPv6 overhead is bigger. This patch changes this validation a bit and now it will works properly for both IPv4 and IPv6 VXLAN tunnels. [1] https://review.openstack.org/#/c/546291/ Change-Id: Ib707312adb45dae7295884aba4ece6538d330d56 Related-Bug: #1744101
This commit is contained in:
parent
4d40e6e40e
commit
60d62d3103
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue