From 4fb8b3fe4e234472b0b0fd6e141eb4035cb0f577 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Wed, 30 Jan 2019 11:16:47 +0000 Subject: [PATCH] Retrieve the device info in trunk_plumber using pyroute2 IPWrapper.get_devices_info(), implemented using pyroute2, retrieves the device information including the VLAN tag and the parent name and index. This patch replaces Plumber._get_vlan_children() shell 'ip' commands in favor of this method. Change-Id: Ib5cad35d5261ab9391f82a22440338d852894a1d Closes-Bug: #1804274 --- .../linuxbridge/agent/trunk_plumber.py | 48 +--------- .../linuxbridge/agent/test_trunk_plumber.py | 91 +++++++------------ 2 files changed, 36 insertions(+), 103 deletions(-) diff --git a/neutron/services/trunk/drivers/linuxbridge/agent/trunk_plumber.py b/neutron/services/trunk/drivers/linuxbridge/agent/trunk_plumber.py index 447f6427259..b6f77ff2491 100644 --- a/neutron/services/trunk/drivers/linuxbridge/agent/trunk_plumber.py +++ b/neutron/services/trunk/drivers/linuxbridge/agent/trunk_plumber.py @@ -10,7 +10,6 @@ # 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 re from neutron_lib.utils import runtime from oslo_concurrency import lockutils @@ -111,46 +110,7 @@ class Plumber(object): def _get_vlan_children(self, dev): """Return set of (devname, vlan_id) tuples for children of device.""" - # TODO(kevinbenton): move into ip-lib after privsep stuff settles - ip_wrapper = ip_lib.IPWrapper(namespace=self.namespace) - output = ip_wrapper.netns.execute(["ip", "-d", "link", "list"], - check_exit_code=True) - return {(i.devname, i.vlan_tag) - for i in _iter_output_by_interface(output) - if i.parent_devname == dev} - - -def _iter_output_by_interface(output): - interface = [] - for line in output.splitlines(): - if not line.startswith(' '): - # no space indicates new interface info - interface_str = ' '.join(interface) - if interface_str.strip(): - yield _InterfaceInfo(interface_str) - interface = [] - interface.append(line) - if interface: - yield _InterfaceInfo(' '.join(interface)) - - -class _InterfaceInfo(object): - def __init__(self, line): - try: - name_section = line.split(': ')[1] - except IndexError: - name_section = None - LOG.warning("Bad interface line: %s", line) - if not name_section or '@' not in name_section: - self.devname = name_section - self.parent_devname = self.vlan_tag = None - else: - self.devname, parent = name_section.split('@') - m = re.match(r'.*802\.1Q id (\d+).*', line) - self.vlan_tag = int(m.group(1)) if m else None - # we only care about parent interfaces if it's a vlan sub-interface - self.parent_devname = parent if self.vlan_tag is not None else None - - def __repr__(self): - return ('_InterfaceInfo(devname=%s, parent=%s, vlan=%s)' % - (self.devname, self.parent_devname, self.vlan_tag)) + devices = ip_lib.get_devices_info(namespace=self.namespace) + return {(device['name'], device['vlan_id']) for device in devices + if device.get('kind') == 'vlan' and + device.get('parent_name') == dev} diff --git a/neutron/tests/unit/services/trunk/drivers/linuxbridge/agent/test_trunk_plumber.py b/neutron/tests/unit/services/trunk/drivers/linuxbridge/agent/test_trunk_plumber.py index 2701258ff49..0c97bc65a87 100644 --- a/neutron/tests/unit/services/trunk/drivers/linuxbridge/agent/test_trunk_plumber.py +++ b/neutron/tests/unit/services/trunk/drivers/linuxbridge/agent/test_trunk_plumber.py @@ -15,11 +15,38 @@ import mock from oslo_utils import uuidutils +from neutron.agent.linux import ip_lib from neutron.objects import trunk from neutron.services.trunk.drivers.linuxbridge.agent import trunk_plumber from neutron.tests import base +IP_LINK_OUTPUT = [ + {'index': 1, 'name': 'lo'}, + {'index': 2, 'name': 'eth0'}, + {'index': 3, 'name': 'bond0'}, + {'index': 4, 'name': 'ovs-system'}, + {'index': 5, 'name': 'br-ex'}, + {'index': 6, 'name': 'testb9cfb5d7'}, + {'index': 7, 'name': 'br-int'}, + {'index': 8, 'name': 'br-tun'}, + {'index': 10, 'name': 'tapa962cfc7-9d'}, + {'index': 11, 'name': 'tap39df7d39-c5', 'kind': 'vlan', + 'parent_name': 'tapa962cfc7-9d', 'vlan_id': 99}, + {'index': 12, 'name': 'tap39df7d44-b2', 'kind': 'vlan', + 'parent_name': 'tapa962cfc7-9d', 'vlan_id': 904}, + {'index': 13, 'name': 'tap11113d44-3f', 'kind': 'vlan', + 'parent_name': 'tapa962cfc7-9d', 'vlan_id': 777}, + {'index': 14, 'name': 'tap34786ac-28'}, + {'index': 15, 'name': 'tap47198374-5a', 'kind': 'vlan', + 'parent_name': 'tap34786ac-28', 'vlan_id': 777}, + {'index': 16, 'name': 'tap47198374-5b', 'kind': 'vlan', + 'parent_name': 'tap34786ac-28', 'vlan_id': 2}, + {'index': 17, 'name': 'tap47198374-5c', 'kind': 'vlan', + 'parent_name': 'tap34786ac-28', 'vlan_id': 3} +] + + class PlumberTestCase(base.BaseTestCase): def setUp(self): self.plumber = trunk_plumber.Plumber() @@ -29,11 +56,11 @@ class PlumberTestCase(base.BaseTestCase): self.trunk = trunk.Trunk() self.trunk.port_id = uuidutils.generate_uuid() self.trunk.sub_ports = [] - self.device_exists = mock.patch.object(trunk_plumber.ip_lib, - 'device_exists').start() + self.device_exists = mock.patch.object(ip_lib, 'device_exists').start() self.device_exists.return_value = True - ipwrap = mock.patch.object(trunk_plumber.ip_lib, 'IPWrapper').start() - ipwrap.return_value.netns.execute.return_value = IP_LINK_OUTPUT + self.mock_get_devices = mock.patch.object(ip_lib, + 'get_devices_info').start() + # ipwrap.return_value.netns.execute.return_value = IP_LINK_OUTPUT super(PlumberTestCase, self).setUp() def test_trunk_on_host(self): @@ -69,6 +96,7 @@ class PlumberTestCase(base.BaseTestCase): any_order=True) def test__get_vlan_children(self): + self.mock_get_devices.return_value = IP_LINK_OUTPUT expected = [('tap47198374-5a', 777), ('tap47198374-5b', 2), ('tap47198374-5c', 3)] @@ -84,58 +112,3 @@ class PlumberTestCase(base.BaseTestCase): self.plumber._get_vlan_children('tap47198374-5c')) self.assertEqual(set(), self.plumber._get_vlan_children('br-int')) - - def test__iter_output_by_interface(self): - iterator = trunk_plumber._iter_output_by_interface(IP_LINK_OUTPUT) - names = [i.devname for i in iterator] - expected = ['lo', 'eth0', 'bond0', 'ovs-system', 'br-ex', - 'testb9cfb5d7', 'br-int', 'br-tun', 'tapa962cfc7-9d', - 'tap39df7d39-c5', 'tap39df7d44-b2', 'tap11113d44-3f', - 'tap34786ac-28', 'tap47198374-5a', 'tap47198374-5b', - 'tap47198374-5c'] - self.assertEqual(expected, names) - - -IP_LINK_OUTPUT = """ -1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group - link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 -2: eth0: mtu 1500 qdisc pfifo_fast state UP mode DEFA - link/ether 00:0c:29:10:68:04 brd ff:ff:ff:ff:ff:ff promiscuity 0 -3: bond0: mtu 1500 qdisc noop state DOWN mode DEFAULT grou - link/ether 5e:dc:86:6f:b7:19 brd ff:ff:ff:ff:ff:ff promiscuity 0 - bond -4: ovs-system: mtu 1500 qdisc noop state DOWN mode DEFAULT group - link/ether 5a:95:a1:b9:42:25 brd ff:ff:ff:ff:ff:ff promiscuity 1 -5: br-ex: mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT gro - link/ether be:cc:4f:f7:28:48 brd ff:ff:ff:ff:ff:ff promiscuity 1 -6: testb9cfb5d7: mtu 1500 qdisc noqueue state UNKNOWN mode DEFA - link/ether 82:90:49:84:32:47 brd ff:ff:ff:ff:ff:ff promiscuity 1 -7: br-int: mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT gr - link/ether 5a:5e:7d:02:7c:4d brd ff:ff:ff:ff:ff:ff promiscuity 1 -8: br-tun: mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT gr - link/ether 76:d8:a5:16:d7:4a brd ff:ff:ff:ff:ff:ff promiscuity 1 -10: tapa962cfc7-9d: mtu 1500 qdisc noop state DOWN mode DEFAULT g - link/ether 9a:31:1d:cc:b3:86 brd ff:ff:ff:ff:ff:ff promiscuity 0 - tun -11: tap39df7d39-c5@tapa962cfc7-9d: mtu 1500 qdisc noop sta - link/ether 9a:31:1d:cc:b3:86 brd ff:ff:ff:ff:ff:ff promiscuity 0 - vlan protocol 802.1Q id 99 -12: tap39df7d44-b2@tapa962cfc7-9d: mtu 1500 qdisc noop sta - link/ether 9a:31:1d:cc:b3:86 brd ff:ff:ff:ff:ff:ff promiscuity 0 - vlan protocol 802.1Q id 904 -13: tap11113d44-3f@tapa962cfc7-9d: mtu 1500 qdisc noop sta - link/ether 9a:31:1d:cc:b3:86 brd ff:ff:ff:ff:ff:ff promiscuity 0 - vlan protocol 802.1Q id 777 -14: tap34786ac-28: mtu 1500 qdisc noop state DOWN mode DEFAULT gr - link/ether f6:07:9f:11:4c:dc brd ff:ff:ff:ff:ff:ff promiscuity 0 - tun -15: tap47198374-5a@tap34786ac-28: mtu 1500 qdisc noop stat - link/ether f6:07:9f:11:4c:dc brd ff:ff:ff:ff:ff:ff promiscuity 0 - vlan protocol 802.1Q id 777 -16: tap47198374-5b@tap34786ac-28: mtu 1500 qdisc noop stat - link/ether f6:07:9f:11:4c:dc brd ff:ff:ff:ff:ff:ff promiscuity 0 - vlan protocol 802.1Q id 2 -17: tap47198374-5c@tap34786ac-28: mtu 1500 qdisc noop stat - link/ether f6:07:9f:11:4c:dc brd ff:ff:ff:ff:ff:ff promiscuity 0 - vlan protocol 802.1Q id 3 -""" # noqa