From b9303e67640ac2052c0a79189b29f60bde6b8fdc Mon Sep 17 00:00:00 2001 From: Kengo Sakai Date: Wed, 22 Jun 2016 16:04:06 +0900 Subject: [PATCH] Check if flavor.vcpus is more than MAX_TAP_QUEUES When attempting to instantiate an instance based on an image with the metadata hw:vif_multiqueue_enabled=true, the code uses flavor.vcpus as the number of queues on a tap interface. In kernels prior to 3.0, multiple queues on a tap interface is not supported[1]. In kernels 3.x, the number of queues on a tap interface is limited to 8 as MAX_TAP_QUEUES in tun driver[2]. From 4.0, the number is 256[3]. If flavor.vcpus is more than MAX_TAP_QUEUES, creating the tap interface fails. This commit adds logic to check if flavor.vcpus is more than MAX_TAP_QUEUES and use MAX_TAP_QUEUES as the number of queues if so. [1]https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/drivers/net/tun.c?id=refs/tags/v2.6.32.71#n101 [2]https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/drivers/net/tun.c?id=refs/tags/v3.18.35#n118 [3]https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/drivers/net/tun.c?id=refs/tags/v4.1.26#n128 Change-Id: I2aa24e3cf550ff69909a2b4bc8be90641dbe3d69 Closes-Bug: #1570631 --- nova/tests/unit/virt/libvirt/test_vif.py | 21 ++++++++++++++--- nova/virt/libvirt/vif.py | 23 ++++++++++++++++++- ...eue-on-tap-interface-2c9e1504fa4590f4.yaml | 12 ++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 releasenotes/notes/multiqueue-on-tap-interface-2c9e1504fa4590f4.yaml diff --git a/nova/tests/unit/virt/libvirt/test_vif.py b/nova/tests/unit/virt/libvirt/test_vif.py index 3f2d0acaacc2..e15fe3938523 100644 --- a/nova/tests/unit/virt/libvirt/test_vif.py +++ b/nova/tests/unit/virt/libvirt/test_vif.py @@ -487,14 +487,14 @@ class LibvirtVifTestCase(test.NoDBTestCase): conf.add_device(nic) return conf.to_xml() - def test_virtio_multiqueue(self): + def _test_virtio_multiqueue(self, vcpus, want_queues): self.flags(use_virtio_for_bridges=True, virt_type='kvm', group='libvirt') flavor = objects.Flavor(name='m1.small', memory_mb=128, - vcpus=4, + vcpus=vcpus, root_gb=0, ephemeral_gb=0, swap=0, @@ -515,7 +515,22 @@ class LibvirtVifTestCase(test.NoDBTestCase): driver = node.find("driver").get("name") self.assertEqual(driver, 'vhost') queues = node.find("driver").get("queues") - self.assertEqual(queues, '4') + self.assertEqual(queues, want_queues) + + def test_virtio_multiqueue(self): + self._test_virtio_multiqueue(4, '4') + + @mock.patch('os.uname', return_value=('Linux', '', '2.6.32-21-generic')) + def test_virtio_multiqueue_in_kernel_2(self, mock_uname): + self._test_virtio_multiqueue(10, '1') + + @mock.patch('os.uname', return_value=('Linux', '', '3.19.0-47-generic')) + def test_virtio_multiqueue_in_kernel_3(self, mock_uname): + self._test_virtio_multiqueue(10, '8') + + @mock.patch('os.uname', return_value=('Linux', '', '4.2.0-35-generic')) + def test_virtio_multiqueue_in_kernel_4(self, mock_uname): + self._test_virtio_multiqueue(10, '10') def test_multiple_nics(self): conf = self._get_conf() diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py index 233d987fbfce..3d8aeab261dd 100644 --- a/nova/virt/libvirt/vif.py +++ b/nova/virt/libvirt/vif.py @@ -148,10 +148,31 @@ class LibvirtGenericVIFDriver(object): img_props = image_meta.properties if img_props.get('hw_vif_multiqueue_enabled'): driver = 'vhost' - vhost_queues = flavor.vcpus + max_tap_queues = self._get_max_tap_queues() + if max_tap_queues: + vhost_queues = (max_tap_queues if flavor.vcpus > max_tap_queues + else flavor.vcpus) + else: + vhost_queues = flavor.vcpus return (driver, vhost_queues) + def _get_max_tap_queues(self): + # NOTE(kengo.sakai): In kernels prior to 3.0, + # multiple queues on a tap interface is not supported. + # In kernels 3.x, the number of queues on a tap interface + # is limited to 8. From 4.0, the number is 256. + # See: https://bugs.launchpad.net/nova/+bug/1570631 + kernel_version = int(os.uname()[2].split(".")[0]) + if kernel_version <= 2: + return 1 + elif kernel_version == 3: + return 8 + elif kernel_version == 4: + return 256 + else: + return None + def get_bridge_name(self, vif): return vif['network']['bridge'] diff --git a/releasenotes/notes/multiqueue-on-tap-interface-2c9e1504fa4590f4.yaml b/releasenotes/notes/multiqueue-on-tap-interface-2c9e1504fa4590f4.yaml new file mode 100644 index 000000000000..cacd5a6fd654 --- /dev/null +++ b/releasenotes/notes/multiqueue-on-tap-interface-2c9e1504fa4590f4.yaml @@ -0,0 +1,12 @@ +--- +fixes: + - | + When instantiating an instance based on an image with the metadata + hw_vif_multiqueue_enabled=true, if flavor.vcpus is less than the limit + of the number of queues on a tap interface in the kernel, nova uses + flavor.vcpus as the number of queues. if not, nova uses the limit. + The limits are as follows: + + * kernels prior to 3.0: 1 + * kernels 3.x: 8 + * kernels 4.x: 256