diff --git a/nova/tests/unit/virt/libvirt/test_config.py b/nova/tests/unit/virt/libvirt/test_config.py
index 358e68608147..b3f1e6013d9e 100644
--- a/nova/tests/unit/virt/libvirt/test_config.py
+++ b/nova/tests/unit/virt/libvirt/test_config.py
@@ -1700,6 +1700,41 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
obj2.parse_str(xml)
self.assertXmlEqual(xml, obj2.to_xml())
+ def test_config_ethernet_with_mtu(self):
+ obj = config.LibvirtConfigGuestInterface()
+ obj.net_type = "ethernet"
+ obj.mac_addr = "DE:AD:BE:EF:CA:FE"
+ obj.model = "virtio"
+ obj.target_dev = "vnet0"
+ obj.driver_name = "vhost"
+ obj.vif_inbound_average = 16384
+ obj.vif_inbound_peak = 32768
+ obj.vif_inbound_burst = 3276
+ obj.vif_outbound_average = 32768
+ obj.vif_outbound_peak = 65536
+ obj.vif_outbound_burst = 6553
+ obj.mtu = 9000
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+
+
+
+
+
+
+
+
+
+
+ """)
+
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
def test_config_driver_options(self):
obj = config.LibvirtConfigGuestInterface()
obj.net_type = "ethernet"
@@ -1762,6 +1797,46 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
obj2.parse_str(xml)
self.assertXmlEqual(xml, obj2.to_xml())
+ def test_config_bridge_with_mtu(self):
+ obj = config.LibvirtConfigGuestInterface()
+ obj.net_type = "bridge"
+ obj.source_dev = "br0"
+ obj.mac_addr = "DE:AD:BE:EF:CA:FE"
+ obj.model = "virtio"
+ obj.target_dev = "tap12345678"
+ obj.filtername = "clean-traffic"
+ obj.filterparams.append({"key": "IP", "value": "192.168.122.1"})
+ obj.vif_inbound_average = 16384
+ obj.vif_inbound_peak = 32768
+ obj.vif_inbound_burst = 3276
+ obj.vif_outbound_average = 32768
+ obj.vif_outbound_peak = 65536
+ obj.vif_outbound_burst = 6553
+ obj.mtu = 9000
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """)
+
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
def test_config_bridge_ovs(self):
obj = config.LibvirtConfigGuestInterface()
obj.net_type = "bridge"
@@ -1790,6 +1865,36 @@ class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
obj2.parse_str(xml)
self.assertXmlEqual(xml, obj2.to_xml())
+ def test_config_bridge_ovs_with_mtu(self):
+ obj = config.LibvirtConfigGuestInterface()
+ obj.net_type = "bridge"
+ obj.source_dev = "br0"
+ obj.mac_addr = "DE:AD:BE:EF:CA:FE"
+ obj.model = "virtio"
+ obj.target_dev = "tap12345678"
+ obj.vporttype = "openvswitch"
+ obj.vportparams.append({"key": "instanceid", "value": "foobar"})
+ obj.mtu = 9000
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+
+
+
+
+
+
+
+
+
+ """)
+
+ # parse the xml from the first object into a new object and make sure
+ # they are the same
+ obj2 = config.LibvirtConfigGuestInterface()
+ obj2.parse_str(xml)
+ self.assertXmlEqual(xml, obj2.to_xml())
+
def test_config_bridge_xen(self):
obj = config.LibvirtConfigGuestInterface()
obj.net_type = "bridge"
diff --git a/nova/tests/unit/virt/libvirt/test_designer.py b/nova/tests/unit/virt/libvirt/test_designer.py
index 7c701eeffc88..da3814a2c8ce 100644
--- a/nova/tests/unit/virt/libvirt/test_designer.py
+++ b/nova/tests/unit/virt/libvirt/test_designer.py
@@ -179,3 +179,8 @@ class DesignerTestCase(test.NoDBTestCase):
self.assertEqual('unix', conf.vhostuser_type)
self.assertEqual('fake-mode', conf.vhostuser_mode)
self.assertEqual('fake-path', conf.vhostuser_path)
+
+ def test_set_vif_mtu_config(self):
+ conf = config.LibvirtConfigGuestInterface()
+ designer.set_vif_mtu_config(conf, 9000)
+ self.assertEqual(9000, conf.mtu)
diff --git a/nova/tests/unit/virt/libvirt/test_vif.py b/nova/tests/unit/virt/libvirt/test_vif.py
index bb6264d19ac2..c30786b0bbe7 100644
--- a/nova/tests/unit/virt/libvirt/test_vif.py
+++ b/nova/tests/unit/virt/libvirt/test_vif.py
@@ -385,7 +385,8 @@ class LibvirtVifTestCase(test.NoDBTestCase):
id="b82c1929-051e-481d-8110-4669916c7915",
label="Demo Net",
subnets=osv_objects.subnet.SubnetList(
- objects=[]))
+ objects=[]),
+ mtu=9000)
self.os_vif_bridge = osv_objects.vif.VIFBridge(
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
@@ -1555,29 +1556,60 @@ class LibvirtVifTestCase(test.NoDBTestCase):
@mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
@mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
- def test_config_os_vif_bridge(self, mock_convert_vif, mock_convert_inst):
+ def test_config_os_vif_bridge(self, mock_convert_vif,
+ mock_convert_inst):
mock_convert_vif.return_value = self.os_vif_bridge
mock_convert_inst.return_value = self.os_vif_inst_info
- d = vif.LibvirtGenericVIFDriver()
hostimpl = host.Host("qemu:///system")
flavor = objects.Flavor(name='m1.small')
image_meta = objects.ImageMeta.from_dict({})
d = vif.LibvirtGenericVIFDriver()
- cfg = d.get_config(self.instance, self.vif_bridge,
- image_meta, flavor,
- CONF.libvirt.virt_type,
- hostimpl)
+ with mock.patch.object(d, "_has_min_version_for_mtu",
+ return_value=True):
+ cfg = d.get_config(self.instance, self.vif_bridge,
+ image_meta, flavor,
+ CONF.libvirt.virt_type,
+ hostimpl)
- self._assertXmlEqual("""
-
-
-
-
-
-
- """, cfg.to_xml())
+ self._assertXmlEqual("""
+
+
+
+
+
+
+
+ """, cfg.to_xml())
+
+ @mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
+ @mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
+ def test_config_os_vif_bridge_no_mtu(self, mock_convert_vif,
+ mock_convert_inst):
+ mock_convert_vif.return_value = self.os_vif_bridge
+ mock_convert_inst.return_value = self.os_vif_inst_info
+
+ hostimpl = host.Host("qemu:///system")
+ flavor = objects.Flavor(name='m1.small')
+ image_meta = objects.ImageMeta.from_dict({})
+ d = vif.LibvirtGenericVIFDriver()
+ with mock.patch.object(d, "_has_min_version_for_mtu",
+ return_value=False):
+ cfg = d.get_config(self.instance, self.vif_bridge,
+ image_meta, flavor,
+ CONF.libvirt.virt_type,
+ hostimpl)
+
+ self._assertXmlEqual("""
+
+
+
+
+
+
+ """, cfg.to_xml())
@mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
@mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
@@ -1588,23 +1620,53 @@ class LibvirtVifTestCase(test.NoDBTestCase):
mock_convert_vif.return_value = self.os_vif_bridge
mock_convert_inst.return_value = self.os_vif_inst_info
- d = vif.LibvirtGenericVIFDriver()
hostimpl = host.Host("qemu:///system")
flavor = objects.Flavor(name='m1.small')
image_meta = objects.ImageMeta.from_dict({})
d = vif.LibvirtGenericVIFDriver()
- cfg = d.get_config(self.instance, self.vif_bridge,
- image_meta, flavor,
- CONF.libvirt.virt_type,
- hostimpl)
+ with mock.patch.object(d, "_has_min_version_for_mtu",
+ return_value=True):
+ cfg = d.get_config(self.instance, self.vif_bridge,
+ image_meta, flavor,
+ CONF.libvirt.virt_type,
+ hostimpl)
- self._assertXmlEqual("""
-
-
-
-
-
- """, cfg.to_xml())
+ self._assertXmlEqual("""
+
+
+
+
+
+
+ """, cfg.to_xml())
+
+ @mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
+ @mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
+ def test_config_os_vif_bridge_nofw_no_mtu(self, mock_convert_vif,
+ mock_convert_inst):
+ self.flags(firewall_driver="nova.virt.firewall.NoopFirewallDriver")
+
+ mock_convert_vif.return_value = self.os_vif_bridge
+ mock_convert_inst.return_value = self.os_vif_inst_info
+
+ hostimpl = host.Host("qemu:///system")
+ flavor = objects.Flavor(name='m1.small')
+ image_meta = objects.ImageMeta.from_dict({})
+ d = vif.LibvirtGenericVIFDriver()
+ with mock.patch.object(d, "_has_min_version_for_mtu",
+ return_value=False):
+ cfg = d.get_config(self.instance, self.vif_bridge,
+ image_meta, flavor,
+ CONF.libvirt.virt_type,
+ hostimpl)
+
+ self._assertXmlEqual("""
+
+
+
+
+
+ """, cfg.to_xml())
@mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
@mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
@@ -1613,27 +1675,60 @@ class LibvirtVifTestCase(test.NoDBTestCase):
mock_convert_vif.return_value = self.os_vif_agilio_ovs
mock_convert_inst.return_value = self.os_vif_inst_info
- d = vif.LibvirtGenericVIFDriver()
hostimpl = host.Host("qemu:///system")
flavor = objects.Flavor(name='m1.small')
image_meta = objects.ImageMeta.from_dict({})
d = vif.LibvirtGenericVIFDriver()
- cfg = d.get_config(self.instance, self.vif_agilio_ovs,
- image_meta, flavor,
- CONF.libvirt.virt_type,
- hostimpl)
+ with mock.patch.object(d, "_has_min_version_for_mtu",
+ return_value=True):
+ cfg = d.get_config(self.instance, self.vif_agilio_ovs,
+ image_meta, flavor,
+ CONF.libvirt.virt_type,
+ hostimpl)
- self._assertXmlEqual("""
-
-
-
-
-
-
-
-
- """, cfg.to_xml())
+ self._assertXmlEqual("""
+
+
+
+
+
+
+
+
+
+ """, cfg.to_xml())
+
+ @mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
+ @mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
+ def test_config_os_vif_agilio_ovs_fallthrough_no_mtu(self,
+ mock_convert_vif,
+ mock_convert_inst):
+ mock_convert_vif.return_value = self.os_vif_agilio_ovs
+ mock_convert_inst.return_value = self.os_vif_inst_info
+
+ hostimpl = host.Host("qemu:///system")
+ flavor = objects.Flavor(name='m1.small')
+ image_meta = objects.ImageMeta.from_dict({})
+ d = vif.LibvirtGenericVIFDriver()
+ with mock.patch.object(d, "_has_min_version_for_mtu",
+ return_value=False):
+ cfg = d.get_config(self.instance, self.vif_agilio_ovs,
+ image_meta, flavor,
+ CONF.libvirt.virt_type,
+ hostimpl)
+
+ self._assertXmlEqual("""
+
+
+
+
+
+
+
+
+ """, cfg.to_xml())
@mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
@mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
@@ -1688,31 +1783,64 @@ class LibvirtVifTestCase(test.NoDBTestCase):
@mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
@mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
- def test_config_os_vif_ovs(self, mock_convert_vif, mock_convert_inst):
+ def test_config_os_vif_ovs(self, mock_convert_vif,
+ mock_convert_inst):
mock_convert_vif.return_value = self.os_vif_ovs
mock_convert_inst.return_value = self.os_vif_inst_info
- d = vif.LibvirtGenericVIFDriver()
hostimpl = host.Host("qemu:///system")
flavor = objects.Flavor(name='m1.small')
image_meta = objects.ImageMeta.from_dict({})
d = vif.LibvirtGenericVIFDriver()
- cfg = d.get_config(self.instance, self.vif_ovs,
- image_meta, flavor,
- CONF.libvirt.virt_type,
- hostimpl)
+ with mock.patch.object(d, "_has_min_version_for_mtu",
+ return_value=True):
+ cfg = d.get_config(self.instance, self.vif_ovs,
+ image_meta, flavor,
+ CONF.libvirt.virt_type,
+ hostimpl)
- self._assertXmlEqual("""
-
-
-
-
-
-
-
-
- """, cfg.to_xml())
+ self._assertXmlEqual("""
+
+
+
+
+
+
+
+
+
+ """, cfg.to_xml())
+
+ @mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
+ @mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
+ def test_config_os_vif_ovs_no_mtu(self, mock_convert_vif,
+ mock_convert_inst):
+ mock_convert_vif.return_value = self.os_vif_ovs
+ mock_convert_inst.return_value = self.os_vif_inst_info
+
+ hostimpl = host.Host("qemu:///system")
+ flavor = objects.Flavor(name='m1.small')
+ image_meta = objects.ImageMeta.from_dict({})
+ d = vif.LibvirtGenericVIFDriver()
+ with mock.patch.object(d, "_has_min_version_for_mtu",
+ return_value=False):
+ cfg = d.get_config(self.instance, self.vif_ovs,
+ image_meta, flavor,
+ CONF.libvirt.virt_type,
+ hostimpl)
+
+ self._assertXmlEqual("""
+
+
+
+
+
+
+
+
+ """, cfg.to_xml())
@mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
@mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
@@ -1721,25 +1849,55 @@ class LibvirtVifTestCase(test.NoDBTestCase):
mock_convert_vif.return_value = self.os_vif_ovs_hybrid
mock_convert_inst.return_value = self.os_vif_inst_info
- d = vif.LibvirtGenericVIFDriver()
hostimpl = host.Host("qemu:///system")
flavor = objects.Flavor(name='m1.small')
image_meta = objects.ImageMeta.from_dict({})
d = vif.LibvirtGenericVIFDriver()
- cfg = d.get_config(self.instance, self.vif_ovs,
- image_meta, flavor,
- CONF.libvirt.virt_type,
- hostimpl)
+ with mock.patch.object(d, "_has_min_version_for_mtu",
+ return_value=True):
+ cfg = d.get_config(self.instance, self.vif_ovs,
+ image_meta, flavor,
+ CONF.libvirt.virt_type,
+ hostimpl)
- self._assertXmlEqual("""
-
-
-
-
-
-
- """, cfg.to_xml())
+ self._assertXmlEqual("""
+
+
+
+
+
+
+
+ """, cfg.to_xml())
+
+ @mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
+ @mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
+ def test_config_os_vif_ovs_hybrid_no_mtu(self, mock_convert_vif,
+ mock_convert_inst):
+ mock_convert_vif.return_value = self.os_vif_ovs_hybrid
+ mock_convert_inst.return_value = self.os_vif_inst_info
+
+ hostimpl = host.Host("qemu:///system")
+ flavor = objects.Flavor(name='m1.small')
+ image_meta = objects.ImageMeta.from_dict({})
+ d = vif.LibvirtGenericVIFDriver()
+ with mock.patch.object(d, "_has_min_version_for_mtu",
+ return_value=False):
+ cfg = d.get_config(self.instance, self.vif_ovs,
+ image_meta, flavor,
+ CONF.libvirt.virt_type,
+ hostimpl)
+
+ self._assertXmlEqual("""
+
+
+
+
+
+
+ """, cfg.to_xml())
@mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
@mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
diff --git a/nova/virt/libvirt/config.py b/nova/virt/libvirt/config.py
index 0c0e6ee0f953..6725ddcac728 100644
--- a/nova/virt/libvirt/config.py
+++ b/nova/virt/libvirt/config.py
@@ -1328,6 +1328,7 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
self.vif_outbound_average = None
self.vlan = None
self.device_addr = None
+ self.mtu = None
def format_dom(self):
dev = super(LibvirtConfigGuestInterface, self).format_dom()
@@ -1348,6 +1349,8 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
if self.net_type == "ethernet":
if self.script is not None:
dev.append(etree.Element("script", path=self.script))
+ if self.mtu is not None:
+ dev.append(etree.Element("mtu", size=str(self.mtu)))
elif self.net_type == "direct":
dev.append(etree.Element("source", dev=self.source_dev,
mode=self.source_mode))
@@ -1370,6 +1373,8 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
dev.append(etree.Element("source", bridge=self.source_dev))
if self.script is not None:
dev.append(etree.Element("script", path=self.script))
+ if self.mtu is not None:
+ dev.append(etree.Element("mtu", size=str(self.mtu)))
else:
dev.append(etree.Element("source", bridge=self.source_dev))
@@ -1501,6 +1506,8 @@ class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
elif c.tag == 'address':
obj = LibvirtConfigGuestDeviceAddress.parse_dom(c)
self.device_addr = obj
+ elif c.tag == 'mtu':
+ self.mtu = int(c.get('size'))
def add_filter_param(self, key, value):
self.filterparams.append({'key': key, 'value': value})
diff --git a/nova/virt/libvirt/designer.py b/nova/virt/libvirt/designer.py
index 847faa65983e..9448847937dc 100644
--- a/nova/virt/libvirt/designer.py
+++ b/nova/virt/libvirt/designer.py
@@ -158,6 +158,13 @@ def set_vif_host_backend_vhostuser_config(conf, mode, path):
conf.vhostuser_path = path
+def set_vif_mtu_config(conf, mtu):
+ """Populate a LibvirtConfigGuestInterface instance
+ with network mtu.
+ """
+ conf.mtu = mtu
+
+
def set_vif_bandwidth_config(conf, inst_type):
"""Config vif inbound/outbound bandwidth limit. parameters are
set in instance_type_extra_specs table, key is in the format
diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py
index 6d5f2385e97d..6b2ad06b33a0 100644
--- a/nova/virt/libvirt/vif.py
+++ b/nova/virt/libvirt/vif.py
@@ -48,6 +48,8 @@ CONF = nova.conf.CONF
MIN_LIBVIRT_VHOSTUSER_MQ = (1, 2, 17)
# vlan tag for macvtap passthrough mode on SRIOV VFs
MIN_LIBVIRT_MACVTAP_PASSTHROUGH_VLAN = (1, 3, 5)
+# setting interface mtu was intoduced in libvirt 3.3
+MIN_LIBVIRT_INTERFACE_MTU = (3, 3, 0)
def is_vif_model_valid_for_virt(virt_type, vif_model):
@@ -237,8 +239,23 @@ class LibvirtGenericVIFDriver(object):
conf.filtername = name
designer.set_vif_bandwidth_config(conf, inst_type)
+ self._set_mtu_config(vif, host, conf)
+
return conf
+ def _set_mtu_config(self, vif, host, conf):
+ """:param vif: nova.network.modle.vif
+ :param host: nova.virt.libvirt.host.Host
+ :param conf: nova.virt.libvirt.config.LibvirtConfigGuestInterface
+ """
+ network = vif.get('network')
+ if (network and network.get_meta("mtu") and
+ self._has_min_version_for_mtu(host)):
+ designer.set_vif_mtu_config(conf, network.get_meta("mtu"))
+
+ def _has_min_version_for_mtu(self, host):
+ return host.has_min_version(MIN_LIBVIRT_INTERFACE_MTU)
+
def get_config_ivs_hybrid(self, instance, vif, image_meta,
inst_type, virt_type, host):
newvif = copy.deepcopy(vif)
@@ -404,6 +421,8 @@ class LibvirtGenericVIFDriver(object):
dev = self.get_vif_devname(vif)
designer.set_vif_host_backend_ethernet_config(conf, dev, host)
+ self._set_mtu_config(vif, host, conf)
+
return conf
def _get_vhostuser_settings(self, vif):
@@ -530,6 +549,9 @@ class LibvirtGenericVIFDriver(object):
func(instance, vif, conf, host)
designer.set_vif_bandwidth_config(conf, inst_type)
+ if ('network' in vif and 'mtu' in vif.network and
+ self._has_min_version_for_mtu(host)):
+ designer.set_vif_mtu_config(conf, vif.network.mtu)
return conf
diff --git a/releasenotes/notes/libvirt-mtu-configuration-0a3e9129dd33b0bc.yaml b/releasenotes/notes/libvirt-mtu-configuration-0a3e9129dd33b0bc.yaml
new file mode 100644
index 000000000000..14a58352078e
--- /dev/null
+++ b/releasenotes/notes/libvirt-mtu-configuration-0a3e9129dd33b0bc.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+ - |
+ For libvirt driver. Now when creating tap devices the MTU will be
+ configured. Requires libvirt 3.3.0 at least.
+