From f9a0c1917c873d5e35afbf96c754a27196be2eb3 Mon Sep 17 00:00:00 2001 From: Michael Still Date: Thu, 29 Mar 2018 15:18:24 +1100 Subject: [PATCH] Move create_tap_dev to the new utility module. Move another generally useful utility method out of nova-net to somewhere more generic. Change-Id: I1bf7afecd2e8122492dcb2c21b26e5b72919e6b5 blueprint: remove-nova-network --- nova/network/linux_net.py | 27 +------ nova/network/linux_utils.py | 25 ++++++ nova/tests/unit/network/test_linux_net.py | 71 ----------------- nova/tests/unit/network/test_utils.py | 95 +++++++++++++++++++++++ nova/tests/unit/virt/libvirt/test_vif.py | 2 +- nova/virt/libvirt/vif.py | 8 +- 6 files changed, 126 insertions(+), 102 deletions(-) create mode 100644 nova/tests/unit/network/test_utils.py diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 4f1c470e952d..0d444c69d1e0 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -1231,31 +1231,6 @@ def _ovs_vsctl(args): raise exception.OvsConfigurationFailure(inner_exception=e) -def create_tap_dev(dev, mac_address=None, multiqueue=False): - if not linux_net_utils.device_exists(dev): - try: - # First, try with 'ip' - 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( - '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: - utils.execute('ip', 'link', 'set', dev, 'address', mac_address, - run_as_root=True, check_exit_code=[0, 2, 254]) - utils.execute('ip', 'link', 'set', dev, 'up', run_as_root=True, - check_exit_code=[0, 2, 254]) - - def create_fp_dev(dev, sockpath, sockmode): if not linux_net_utils.device_exists(dev): utils.execute('fp-vdev', 'add', dev, '--sockpath', sockpath, @@ -1755,7 +1730,7 @@ class NeutronLinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver): for rule in get_gateway_rules(bridge): iptables_manager.ipv4['filter'].add_rule(*rule) - create_tap_dev(dev, mac_address) + linux_net_utils.create_tap_dev(dev, mac_address) if not linux_net_utils.device_exists(bridge): LOG.debug("Starting bridge %s ", bridge) diff --git a/nova/network/linux_utils.py b/nova/network/linux_utils.py index e7967a091192..8498b8010f82 100644 --- a/nova/network/linux_utils.py +++ b/nova/network/linux_utils.py @@ -68,3 +68,28 @@ def create_veth_pair(dev1_name, dev2_name, mtu=None): utils.execute('ip', 'link', 'set', dev, 'promisc', 'on', run_as_root=True) set_device_mtu(dev, mtu) + + +def create_tap_dev(dev, mac_address=None, multiqueue=False): + if not device_exists(dev): + try: + # First, try with 'ip' + 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( + '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: + utils.execute('ip', 'link', 'set', dev, 'address', mac_address, + run_as_root=True, check_exit_code=[0, 2, 254]) + utils.execute('ip', 'link', 'set', dev, 'up', run_as_root=True, + check_exit_code=[0, 2, 254]) diff --git a/nova/tests/unit/network/test_linux_net.py b/nova/tests/unit/network/test_linux_net.py index 18daff8d313b..0f1fde36a6c7 100644 --- a/nova/tests/unit/network/test_linux_net.py +++ b/nova/tests/unit/network/test_linux_net.py @@ -1340,77 +1340,6 @@ class LinuxNetworkTestCase(test.NoDBTestCase): 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) - @mock.patch('nova.pci.utils.get_vf_num_by_pci_address') @mock.patch('nova.pci.utils.get_ifname_by_pci_address') @mock.patch('nova.utils.execute') diff --git a/nova/tests/unit/network/test_utils.py b/nova/tests/unit/network/test_utils.py new file mode 100644 index 000000000000..0a666c1086fa --- /dev/null +++ b/nova/tests/unit/network/test_utils.py @@ -0,0 +1,95 @@ +# Copyright 2011 NTT +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +import mock + +from oslo_concurrency import processutils + +from nova.network import linux_utils as net_utils +from nova import test + + +class NetUtilsTestCase(test.NoDBTestCase): + @mock.patch('nova.utils.execute') + def test_create_tap_dev(self, mock_execute): + net_utils.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): + net_utils.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): + net_utils.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] + + net_utils.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): + net_utils.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, + net_utils.create_tap_dev, + 'tap42', multiqueue=True) diff --git a/nova/tests/unit/virt/libvirt/test_vif.py b/nova/tests/unit/virt/libvirt/test_vif.py index 902c9738ad87..6469809957d5 100644 --- a/nova/tests/unit/virt/libvirt/test_vif.py +++ b/nova/tests/unit/virt/libvirt/test_vif.py @@ -979,7 +979,7 @@ class LibvirtVifTestCase(test.NoDBTestCase): 'NovaVMPort', self.vif_vrouter['devname'], self.vif_vrouter['address'], '0.0.0.0', None) - @mock.patch('nova.network.linux_net.create_tap_dev') + @mock.patch('nova.network.linux_utils.create_tap_dev') @mock.patch('nova.privsep.libvirt.plug_contrail_vif') def test_plug_vrouter_with_details_multiqueue( self, mock_plug_contrail, mock_create_tap_dev): diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py index 5be6c96da1cd..9903f07aef93 100644 --- a/nova/virt/libvirt/vif.py +++ b/nova/virt/libvirt/vif.py @@ -644,7 +644,7 @@ class LibvirtGenericVIFDriver(object): dev = self.get_vif_devname(vif) port_id = vif['id'] try: - linux_net.create_tap_dev(dev) + linux_net_utils.create_tap_dev(dev) nova.privsep.libvirt.plug_midonet_vif(port_id, dev) except processutils.ProcessExecutionError: LOG.exception(_("Failed while plugging vif"), instance=instance) @@ -657,7 +657,7 @@ class LibvirtGenericVIFDriver(object): """ dev = self.get_vif_devname(vif) iface_id = vif['id'] - linux_net.create_tap_dev(dev) + linux_net_utils.create_tap_dev(dev) net_id = vif['network']['id'] tenant_id = instance.project_id try: @@ -670,7 +670,7 @@ class LibvirtGenericVIFDriver(object): """Plug a VIF_TYPE_TAP virtual interface.""" dev = self.get_vif_devname(vif) mac = vif['details'].get(network_model.VIF_DETAILS_TAP_MAC_ADDRESS) - linux_net.create_tap_dev(dev, mac) + linux_net_utils.create_tap_dev(dev, mac) network = vif.get('network') mtu = network.get_meta('mtu') if network else None linux_net_utils.set_device_mtu(dev, mtu) @@ -707,7 +707,7 @@ class LibvirtGenericVIFDriver(object): try: multiqueue = self._is_multiqueue_enabled(instance.image_meta, instance.flavor) - linux_net.create_tap_dev(dev, multiqueue=multiqueue) + linux_net_utils.create_tap_dev(dev, multiqueue=multiqueue) nova.privsep.libvirt.plug_contrail_vif( instance.project_id, instance.uuid,