diff -Nru neutron-2014.1.5/debian/changelog neutron-2014.1.5/debian/changelog --- neutron-2014.1.5/debian/changelog 2016-08-29 18:06:06.000000000 -0400 +++ neutron-2014.1.5/debian/changelog 2016-11-03 16:53:31.000000000 -0400 @@ -1,3 +1,12 @@ +neutron (1:2014.1.5-0ubuntu7) UNRELEASED; urgency=medium + + * agent/linux/ip_lib.py does not correctly handle output from 'iproute2' + command. (LP: #1374663): + - d/p/neutron-ns-iface-enum.patch: Searches /sys/class/net for the correct + interface name instead of scraping iproute2 output. + + -- Shane Peters (Shaner) Thu, 03 Nov 2016 16:53:31 -0400 + neutron (1:2014.1.5-0ubuntu6) trusty; urgency=medium * iptables_manager can run very slowly when a large number of security group diff -Nru neutron-2014.1.5/debian/patches/neutron-ns-iface-enum.patch neutron-2014.1.5/debian/patches/neutron-ns-iface-enum.patch --- neutron-2014.1.5/debian/patches/neutron-ns-iface-enum.patch 1969-12-31 19:00:00.000000000 -0500 +++ neutron-2014.1.5/debian/patches/neutron-ns-iface-enum.patch 2016-11-03 16:53:20.000000000 -0400 @@ -0,0 +1,245 @@ +From 8242e9c136199ce7ce1aa0bd31f196827da4741d Mon Sep 17 00:00:00 2001 +From: Matthew Thode +Date: Mon, 9 Feb 2015 11:02:58 -0600 +Subject: [PATCH] replaces enumeration method used to get a list of interfaces + +ip_lib was parsing tunnel links incorrectly. We can create interface +names with any character the filesystem supports (not '..', '/', ':'). +Given this we do not know what to delimit on so parsing iproute2 output +is probably not a good idea. + +I asked the iproute2 devs what the proper way we should get interface +names is and was told NOT to parse iproute2 output but to use something +like sysfs instead. http://www.spinics.net/lists/netdev/msg316577.html + +This patch pulls interfaces from sysfs (/sys/class/net) and verifies them +via checking if they are links (bonding creates files for instance and +needs to be skipped). + +Currently it is not possible without jumping through a ton of hoops to +access a network namespace without iproute2 or cython, so we use ip to +run find to find the correct sysfs directory. We also only call out to +iproute2 _ONLY_ if needed. + +Change-Id: I07d1d297f07857d216649cccf717896574aac301 +Closes-Bug: 1374663 +(cherry picked from commit c717a6365c1aecb0e3957f0857a06f2334f99d5d) + + Conflicts: + neutron/agent/linux/ip_lib.py + neutron/tests/unit/test_linux_ip_lib.py +--- + etc/neutron/rootwrap.d/dhcp.filters | 1 + + etc/neutron/rootwrap.d/l3.filters | 1 + + etc/neutron/rootwrap.d/linuxbridge-plugin.filters | 1 + + etc/neutron/rootwrap.d/openvswitch-plugin.filters | 1 + + etc/neutron/rootwrap.d/vpnaas.filters | 1 + + neutron/agent/linux/ip_lib.py | 43 ++++++++-------- + neutron/tests/unit/test_linux_ip_lib.py | 63 +++++++---------------- + 7 files changed, 46 insertions(+), 65 deletions(-) + +Index: neutron-2014.1.5/etc/neutron/rootwrap.d/dhcp.filters +=================================================================== +--- neutron-2014.1.5.orig/etc/neutron/rootwrap.d/dhcp.filters ++++ neutron-2014.1.5/etc/neutron/rootwrap.d/dhcp.filters +@@ -35,4 +35,5 @@ kill_metadata6: KillFilter, root, /usr/b + + # ip_lib + ip: IpFilter, ip, root ++find: RegExpFilter, find, root, find, /sys/class/net, -maxdepth, 1, -type, l, -printf, %.* + ip_exec: IpNetnsExecFilter, ip, root +Index: neutron-2014.1.5/etc/neutron/rootwrap.d/l3.filters +=================================================================== +--- neutron-2014.1.5.orig/etc/neutron/rootwrap.d/l3.filters ++++ neutron-2014.1.5/etc/neutron/rootwrap.d/l3.filters +@@ -29,6 +29,7 @@ kill_metadata6: KillFilter, root, /usr/b + + # ip_lib + ip: IpFilter, ip, root ++find: RegExpFilter, find, root, find, /sys/class/net, -maxdepth, 1, -type, l, -printf, %.* + ip_exec: IpNetnsExecFilter, ip, root + + # ovs_lib (if OVSInterfaceDriver is used) +Index: neutron-2014.1.5/etc/neutron/rootwrap.d/linuxbridge-plugin.filters +=================================================================== +--- neutron-2014.1.5.orig/etc/neutron/rootwrap.d/linuxbridge-plugin.filters ++++ neutron-2014.1.5/etc/neutron/rootwrap.d/linuxbridge-plugin.filters +@@ -16,4 +16,5 @@ bridge: CommandFilter, bridge, root + + # ip_lib + ip: IpFilter, ip, root ++find: RegExpFilter, find, root, find, /sys/class/net, -maxdepth, 1, -type, l, -printf, %.* + ip_exec: IpNetnsExecFilter, ip, root +Index: neutron-2014.1.5/etc/neutron/rootwrap.d/openvswitch-plugin.filters +=================================================================== +--- neutron-2014.1.5.orig/etc/neutron/rootwrap.d/openvswitch-plugin.filters ++++ neutron-2014.1.5/etc/neutron/rootwrap.d/openvswitch-plugin.filters +@@ -19,4 +19,5 @@ xe: CommandFilter, xe, root + + # ip_lib + ip: IpFilter, ip, root ++find: RegExpFilter, find, root, find, /sys/class/net, -maxdepth, 1, -type, l, -printf, %.* + ip_exec: IpNetnsExecFilter, ip, root +Index: neutron-2014.1.5/etc/neutron/rootwrap.d/vpnaas.filters +=================================================================== +--- neutron-2014.1.5.orig/etc/neutron/rootwrap.d/vpnaas.filters ++++ neutron-2014.1.5/etc/neutron/rootwrap.d/vpnaas.filters +@@ -9,5 +9,6 @@ + [Filters] + + ip: IpFilter, ip, root ++find: RegExpFilter, find, root, find, /sys/class/net, -maxdepth, 1, -type, l, -printf, %.* + ip_exec: IpNetnsExecFilter, ip, root + openswan: CommandFilter, ipsec, root +Index: neutron-2014.1.5/neutron/agent/linux/ip_lib.py +=================================================================== +--- neutron-2014.1.5.orig/neutron/agent/linux/ip_lib.py ++++ neutron-2014.1.5/neutron/agent/linux/ip_lib.py +@@ -16,6 +16,7 @@ + + import netaddr + from oslo.config import cfg ++import os + + from neutron.agent.linux import utils + from neutron.common import exceptions +@@ -30,11 +31,8 @@ OPTS = [ + + VETH_MAX_NAME_LENGTH = 15 + LOOPBACK_DEVNAME = 'lo' +-# NOTE(ethuleau): depend of the version of iproute2, the vlan +-# interface details vary. +-VLAN_INTERFACE_DETAIL = ['vlan protocol 802.1q', +- 'vlan protocol 802.1Q', +- 'vlan id'] ++ ++SYS_NET_PATH = '/sys/class/net' + + + class SubProcessBase(object): +@@ -93,25 +91,26 @@ class IPWrapper(SubProcessBase): + + def get_devices(self, exclude_loopback=False): + retval = [] +- output = self._execute(['o', 'd'], 'link', ('list',), +- self.root_helper, self.namespace) +- for line in output.split('\n'): +- if '<' not in line: ++ if self.namespace: ++ # we call out manually because in order to avoid screen scraping ++ # iproute2 we use find to see what is in the sysfs directory, as ++ # suggested by Stephen Hemminger (iproute2 dev). ++ output = utils.execute(['ip', 'netns', 'exec', self.namespace, ++ 'find', SYS_NET_PATH, '-maxdepth', '1', ++ '-type', 'l', '-printf', '%f '], ++ root_helper=self.root_helper).split() ++ ++ else: ++ output = ( ++ i for i in os.listdir(SYS_NET_PATH) ++ if os.path.islink(os.path.join(SYS_NET_PATH, i)) ++ ) ++ ++ for name in output: ++ if exclude_loopback and name == LOOPBACK_DEVNAME: + continue +- tokens = line.split(' ', 2) +- if len(tokens) == 3: +- if any(v in tokens[2] for v in VLAN_INTERFACE_DETAIL): +- delimiter = '@' +- else: +- delimiter = ':' +- name = tokens[1].rpartition(delimiter)[0].strip() +- +- if exclude_loopback and name == LOOPBACK_DEVNAME: +- continue +- +- retval.append(IPDevice(name, +- self.root_helper, +- self.namespace)) ++ retval.append(IPDevice(name, namespace=self.namespace)) ++ + return retval + + def add_tuntap(self, name, mode='tap'): +Index: neutron-2014.1.5/neutron/tests/unit/test_linux_ip_lib.py +=================================================================== +--- neutron-2014.1.5.orig/neutron/tests/unit/test_linux_ip_lib.py ++++ neutron-2014.1.5/neutron/tests/unit/test_linux_ip_lib.py +@@ -18,6 +18,7 @@ + import mock + + from neutron.agent.linux import ip_lib ++from neutron.agent.linux import utils # noqa + from neutron.common import exceptions + from neutron.tests import base + +@@ -202,49 +203,25 @@ class TestIpWrapper(base.BaseTestCase): + self.execute = self.execute_p.start() + self.addCleanup(self.execute_p.stop) + +- def test_get_devices(self): +- self.execute.return_value = '\n'.join(LINK_SAMPLE) +- retval = ip_lib.IPWrapper('sudo').get_devices() +- self.assertEqual(retval, +- [ip_lib.IPDevice('lo'), +- ip_lib.IPDevice('eth0'), +- ip_lib.IPDevice('br-int'), +- ip_lib.IPDevice('gw-ddc717df-49'), +- ip_lib.IPDevice('foo:foo'), +- ip_lib.IPDevice('foo@foo'), +- ip_lib.IPDevice('foo:foo@foo'), +- ip_lib.IPDevice('foo@foo:foo'), +- ip_lib.IPDevice('bar.9'), +- ip_lib.IPDevice('bar'), +- ip_lib.IPDevice('bar:bar'), +- ip_lib.IPDevice('bar@bar'), +- ip_lib.IPDevice('bar:bar@bar'), +- ip_lib.IPDevice('bar@bar:bar')]) +- +- self.execute.assert_called_once_with(['o', 'd'], 'link', ('list',), +- 'sudo', None) +- +- def test_get_devices_malformed_line(self): +- self.execute.return_value = '\n'.join(LINK_SAMPLE + ['gibberish']) +- retval = ip_lib.IPWrapper('sudo').get_devices() +- self.assertEqual(retval, +- [ip_lib.IPDevice('lo'), +- ip_lib.IPDevice('eth0'), +- ip_lib.IPDevice('br-int'), +- ip_lib.IPDevice('gw-ddc717df-49'), +- ip_lib.IPDevice('foo:foo'), +- ip_lib.IPDevice('foo@foo'), +- ip_lib.IPDevice('foo:foo@foo'), +- ip_lib.IPDevice('foo@foo:foo'), +- ip_lib.IPDevice('bar.9'), +- ip_lib.IPDevice('bar'), +- ip_lib.IPDevice('bar:bar'), +- ip_lib.IPDevice('bar@bar'), +- ip_lib.IPDevice('bar:bar@bar'), +- ip_lib.IPDevice('bar@bar:bar')]) +- +- self.execute.assert_called_once_with(['o', 'd'], 'link', ('list',), +- 'sudo', None) ++ @mock.patch('os.path.islink') ++ @mock.patch('os.listdir', return_value=['lo']) ++ def test_get_devices(self, mocked_listdir, mocked_islink): ++ retval = ip_lib.IPWrapper().get_devices() ++ mocked_islink.assert_called_once_with('/sys/class/net/lo') ++ self.assertEqual(retval, [ip_lib.IPDevice('lo')]) ++ ++ @mock.patch('neutron.agent.linux.utils.execute') ++ def test_get_devices_namespaces(self, mocked_execute): ++ fake_str = mock.Mock() ++ fake_str.split.return_value = ['lo'] ++ mocked_execute.return_value = fake_str ++ retval = ip_lib.IPWrapper(namespace='foo').get_devices() ++ mocked_execute.assert_called_once_with( ++ ['ip', 'netns', 'exec', 'foo', 'find', '/sys/class/net', ++ '-maxdepth', '1', '-type', 'l', '-printf', '%f '], ++ root_helper=None) ++ self.assertTrue(fake_str.split.called) ++ self.assertEqual(retval, [ip_lib.IPDevice('lo', namespace='foo')]) + + def test_get_namespaces(self): + self.execute.return_value = '\n'.join(NETNS_SAMPLE) diff -Nru neutron-2014.1.5/debian/patches/series neutron-2014.1.5/debian/patches/series --- neutron-2014.1.5/debian/patches/series 2016-08-29 18:06:06.000000000 -0400 +++ neutron-2014.1.5/debian/patches/series 2016-11-03 16:52:52.000000000 -0400 @@ -8,3 +8,4 @@ fix-neutron-agent-fanout-queue-not-found-loop.patch refactor-log-in-loop.patch use-dictionary-for-iptables-find.patch +neutron-ns-iface-enum.patch