linux_net: allow for creation of multiqueue taps

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
This commit is contained in:
Roman Podoliaka 2016-11-01 15:50:19 +02:00
parent d49f901b43
commit 41d601851d
2 changed files with 83 additions and 3 deletions

View 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:

View 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)