]> xenbits.xensource.com Git - osstest/openstack-nova.git/commitdiff
linux_net: allow for creation of multiqueue taps
authorRoman Podoliaka <rpodolyaka@mirantis.com>
Tue, 1 Nov 2016 13:50:19 +0000 (15:50 +0200)
committerRoman Podoliaka <rpodolyaka@mirantis.com>
Thu, 24 Nov 2016 13:49:18 +0000 (15:49 +0200)
This is useful for e.g. enabling multiqueue support for vrouter: tap
devices created by Nova and then passed to libvirt must have
multiqueue enabled.

Implements blueprint vif-vrouter-multiqueue

Co-Authored-By: Michal Dubiel <md@semihalf.com>
Change-Id: I7170bf7c181b038bb3d70a3b86c87ee254d10efc

nova/network/linux_net.py
nova/tests/unit/network/test_linux_net.py

index b10fa287df65b3e9cd85a82e425a49cc4d6504da..1e06a7a1200f616ef6992ae668909971404555c0 100644 (file)
@@ -1311,13 +1311,22 @@ def delete_ivs_vif_port(dev):
                   run_as_root=True)
 
 
-def create_tap_dev(dev, mac_address=None):
+def create_tap_dev(dev, mac_address=None, multiqueue=False):
     if not device_exists(dev):
         try:
             # First, try with 'ip'
-            utils.execute('ip', 'tuntap', 'add', dev, 'mode', 'tap',
-                          run_as_root=True, check_exit_code=[0, 2, 254])
+            cmd = ('ip', 'tuntap', 'add', dev, 'mode', 'tap')
+            if multiqueue:
+                cmd = cmd + ('multi_queue', )
+            utils.execute(*cmd, run_as_root=True, check_exit_code=[0, 2, 254])
         except processutils.ProcessExecutionError:
+            if multiqueue:
+                LOG.warning(
+                    _LW('Failed to create a tap device with ip tuntap. '
+                        'tunctl does not support creation of multi-queue '
+                        'enabled devices, skipping fallback.'))
+                raise
+
             # Second option: tunctl
             utils.execute('tunctl', '-b', '-t', dev, run_as_root=True)
         if mac_address:
index 4b90da50f62d4472606c1071234a6edf97bcc70c..6e65a86669faedc9e85554c4545ab10fa82f66bd 100644 (file)
@@ -1418,3 +1418,74 @@ class LinuxNetworkTestCase(test.NoDBTestCase):
         self.assertRaises(processutils.ProcessExecutionError,
                           linux_net.LinuxBridgeInterfaceDriver.remove_bridge,
                           'fake-bridge')
+
+    @mock.patch('nova.utils.execute')
+    def test_create_tap_dev(self, mock_execute):
+        linux_net.create_tap_dev('tap42')
+
+        mock_execute.assert_has_calls([
+            mock.call('ip', 'tuntap', 'add', 'tap42', 'mode', 'tap',
+                      run_as_root=True, check_exit_code=[0, 2, 254]),
+            mock.call('ip', 'link', 'set', 'tap42', 'up',
+                      run_as_root=True, check_exit_code=[0, 2, 254])
+        ])
+
+    @mock.patch('os.path.exists', return_value=True)
+    @mock.patch('nova.utils.execute')
+    def test_create_tap_skipped_when_exists(self, mock_execute, mock_exists):
+        linux_net.create_tap_dev('tap42')
+
+        mock_exists.assert_called_once_with('/sys/class/net/tap42')
+        mock_execute.assert_not_called()
+
+    @mock.patch('nova.utils.execute')
+    def test_create_tap_dev_mac(self, mock_execute):
+        linux_net.create_tap_dev('tap42', '00:11:22:33:44:55')
+
+        mock_execute.assert_has_calls([
+            mock.call('ip', 'tuntap', 'add', 'tap42', 'mode', 'tap',
+                      run_as_root=True, check_exit_code=[0, 2, 254]),
+            mock.call('ip', 'link', 'set', 'tap42',
+                      'address', '00:11:22:33:44:55',
+                      run_as_root=True, check_exit_code=[0, 2, 254]),
+            mock.call('ip', 'link', 'set', 'tap42', 'up',
+                      run_as_root=True, check_exit_code=[0, 2, 254])
+        ])
+
+    @mock.patch('nova.utils.execute')
+    def test_create_tap_dev_fallback_to_tunctl(self, mock_execute):
+        # ip failed, fall back to tunctl
+        mock_execute.side_effect = [processutils.ProcessExecutionError, 0, 0]
+
+        linux_net.create_tap_dev('tap42')
+
+        mock_execute.assert_has_calls([
+            mock.call('ip', 'tuntap', 'add', 'tap42', 'mode', 'tap',
+                      run_as_root=True, check_exit_code=[0, 2, 254]),
+            mock.call('tunctl', '-b', '-t', 'tap42',
+                      run_as_root=True),
+            mock.call('ip', 'link', 'set', 'tap42', 'up',
+                      run_as_root=True, check_exit_code=[0, 2, 254])
+        ])
+
+    @mock.patch('nova.utils.execute')
+    def test_create_tap_dev_multiqueue(self, mock_execute):
+        linux_net.create_tap_dev('tap42', multiqueue=True)
+
+        mock_execute.assert_has_calls([
+            mock.call('ip', 'tuntap', 'add', 'tap42', 'mode', 'tap',
+                      'multi_queue',
+                      run_as_root=True, check_exit_code=[0, 2, 254]),
+            mock.call('ip', 'link', 'set', 'tap42', 'up',
+                      run_as_root=True, check_exit_code=[0, 2, 254])
+        ])
+
+    @mock.patch('nova.utils.execute')
+    def test_create_tap_dev_multiqueue_tunctl_raises(self, mock_execute):
+        # if creation of a tap by the means of ip command fails,
+        # create_tap_dev() will try to do that by the means of tunctl
+        mock_execute.side_effect = processutils.ProcessExecutionError
+        # but tunctl can't create multiqueue taps, so the failure is expected
+        self.assertRaises(processutils.ProcessExecutionError,
+                          linux_net.create_tap_dev,
+                          'tap42', multiqueue=True)