From e6708f6d47dc0bfdde3c9ced5066857c695ff717 Mon Sep 17 00:00:00 2001 From: Neil Jerram Date: Mon, 27 Jul 2015 14:43:18 +0100 Subject: [PATCH] ip_lib: support creating Linux dummy interface This is for use by a DHCP agent interface driver in the networking-calico project. networking-calico connects VMs without using bridging, so it needs an unbridged DHCP port interface with which it can associate the DHCP subnet prefix, and the Linux dummy interface (in conjunction with use of Dnsmasq's --bridge-interface feature) is suitable for that purpose. Partial-Bug: #1486649 Change-Id: I5485c187bc44bac3c2942c4fc9e5a502912a81a2 --- neutron/agent/linux/ip_lib.py | 5 +++++ .../tests/functional/agent/linux/test_ip_lib.py | 14 ++++++++++++++ neutron/tests/unit/agent/linux/test_ip_lib.py | 8 ++++++++ 3 files changed, 27 insertions(+) diff --git a/neutron/agent/linux/ip_lib.py b/neutron/agent/linux/ip_lib.py index cadbd019f..7c4b4e37a 100644 --- a/neutron/agent/linux/ip_lib.py +++ b/neutron/agent/linux/ip_lib.py @@ -152,6 +152,11 @@ class IPWrapper(SubProcessBase): """Delete a virtual interface between two namespaces.""" self._as_root([], 'link', ('del', name)) + def add_dummy(self, name): + """Create a Linux dummy interface with the given name.""" + self._as_root([], 'link', ('add', name, 'type', 'dummy')) + return IPDevice(name, namespace=self.namespace) + def ensure_namespace(self, name): if not self.netns.exists(name): ip = self.netns.add(name) diff --git a/neutron/tests/functional/agent/linux/test_ip_lib.py b/neutron/tests/functional/agent/linux/test_ip_lib.py index 4e8316f77..b166b0ec5 100644 --- a/neutron/tests/functional/agent/linux/test_ip_lib.py +++ b/neutron/tests/functional/agent/linux/test_ip_lib.py @@ -24,6 +24,7 @@ from neutron.agent.common import config from neutron.agent.linux import interface from neutron.agent.linux import ip_lib from neutron.common import utils +from neutron.tests.common import net_helpers from neutron.tests.functional.agent.linux import base from neutron.tests.functional import base as functional_base @@ -164,3 +165,16 @@ class IpLibTestCase(IpLibTestFramework): routes = ip_lib.get_routing_table(4, namespace=attr.namespace) self.assertEqual(expected_routes, routes) + + def _check_for_device_name(self, ip, name, should_exist): + exist = any(d for d in ip.get_devices() if d.name == name) + self.assertEqual(should_exist, exist) + + def test_dummy_exists(self): + namespace = self.useFixture(net_helpers.NamespaceFixture()) + dev_name = base.get_rand_name() + device = namespace.ip_wrapper.add_dummy(dev_name) + self.addCleanup(self._safe_delete_device, device) + self._check_for_device_name(namespace.ip_wrapper, dev_name, True) + device.link.delete() + self._check_for_device_name(namespace.ip_wrapper, dev_name, False) diff --git a/neutron/tests/unit/agent/linux/test_ip_lib.py b/neutron/tests/unit/agent/linux/test_ip_lib.py index 87a2a8227..81e310d01 100644 --- a/neutron/tests/unit/agent/linux/test_ip_lib.py +++ b/neutron/tests/unit/agent/linux/test_ip_lib.py @@ -313,6 +313,14 @@ class TestIpWrapper(base.BaseTestCase): run_as_root=True, namespace=None, log_fail_as_error=True) + def test_add_dummy(self): + ip_lib.IPWrapper().add_dummy('dummy0') + self.execute.assert_called_once_with([], 'link', + ('add', 'dummy0', + 'type', 'dummy'), + run_as_root=True, namespace=None, + log_fail_as_error=True) + def test_get_device(self): dev = ip_lib.IPWrapper(namespace='ns').device('eth0') self.assertEqual(dev.namespace, 'ns') -- 2.45.2