From 4dc68ea88bf4f07b13253bf9eeedffe22b1f8013 Mon Sep 17 00:00:00 2001 From: Kevin Benton Date: Thu, 28 May 2015 23:13:19 -0700 Subject: [PATCH 1/5] Read vif port information in bulk During startup, the agent was making many calls per port to read information about the current VLAN, external ID, etc. This resulted in hundreds of calls just to read information about a relatively small number of ports. This patch addresses that by converting a few key functions to lookup information for all of the ports at once. Performance improvement on dev laptop for 250 ports from agent start to port ACTIVE status: before: 1m21s after: 1m06s Closes-Bug: #1460233 Change-Id: Ic80c85a07fee3e5651dc19819c6cebdc2048dda7 --- neutron/agent/common/ovs_lib.py | 71 ++++++++++++++----- .../openvswitch/agent/ovs_neutron_agent.py | 22 ++++-- .../tests/functional/agent/test_ovs_lib.py | 9 +++ .../tests/unit/agent/common/test_ovs_lib.py | 44 +++++++++--- .../agent/test_ovs_neutron_agent.py | 27 +++++-- .../openvswitch/agent/test_ovs_tunnel.py | 5 +- 6 files changed, 138 insertions(+), 40 deletions(-) diff --git a/neutron/agent/common/ovs_lib.py b/neutron/agent/common/ovs_lib.py index 81340c59888..6db93474cec 100644 --- a/neutron/agent/common/ovs_lib.py +++ b/neutron/agent/common/ovs_lib.py @@ -141,6 +141,12 @@ class BaseOVS(object): return self.ovsdb.db_get(table, record, column).execute( check_error=check_error, log_errors=log_errors) + def db_list(self, table, records=None, columns=None, + check_error=True, log_errors=True, if_exists=False): + return (self.ovsdb.db_list(table, records=records, columns=columns, + if_exists=if_exists). + execute(check_error=check_error, log_errors=log_errors)) + class OVSBridge(BaseOVS): def __init__(self, br_name): @@ -319,11 +325,12 @@ class OVSBridge(BaseOVS): def get_vif_ports(self): edge_ports = [] port_names = self.get_port_name_list() + port_info = self.db_list( + 'Interface', columns=['name', 'external_ids', 'ofport']) + by_name = {x['name']: x for x in port_info} for name in port_names: - external_ids = self.db_get_val("Interface", name, "external_ids", - check_error=True) - ofport = self.db_get_val("Interface", name, "ofport", - check_error=True) + external_ids = by_name[name]['external_ids'] + ofport = by_name[name]['ofport'] if "iface-id" in external_ids and "attached-mac" in external_ids: p = VifPort(name, ofport, external_ids["iface-id"], external_ids["attached-mac"], self) @@ -341,10 +348,9 @@ class OVSBridge(BaseOVS): def get_vif_port_to_ofport_map(self): port_names = self.get_port_name_list() - cmd = self.ovsdb.db_list( - 'Interface', port_names, - columns=['name', 'external_ids', 'ofport'], if_exists=True) - results = cmd.execute(check_error=True) + results = self.db_list( + 'Interface', port_names, ['name', 'external_ids', 'ofport'], + if_exists=True) port_map = {} for r in results: # fall back to basic interface name @@ -359,10 +365,9 @@ class OVSBridge(BaseOVS): def get_vif_port_set(self): edge_ports = set() port_names = self.get_port_name_list() - cmd = self.ovsdb.db_list( - 'Interface', port_names, - columns=['name', 'external_ids', 'ofport'], if_exists=True) - results = cmd.execute(check_error=True) + results = self.db_list( + 'Interface', port_names, ['name', 'external_ids', 'ofport'], + if_exists=True) for result in results: if result['ofport'] == UNASSIGNED_OFPORT: LOG.warn(_LW("Found not yet ready openvswitch port: %s"), @@ -400,11 +405,42 @@ class OVSBridge(BaseOVS): """ port_names = self.get_port_name_list() - cmd = self.ovsdb.db_list('Port', port_names, columns=['name', 'tag'], - if_exists=True) - results = cmd.execute(check_error=True) + results = self.db_list('Port', port_names, ['name', 'tag'], + if_exists=True) return {p['name']: p['tag'] for p in results} + def get_vifs_by_ids(self, port_ids): + interface_info = self.db_list( + "Interface", columns=["name", "external_ids", "ofport"]) + by_id = {x['external_ids'].get('iface-id'): x for x in interface_info} + intfs_on_bridge = self.ovsdb.list_ports(self.br_name).execute( + check_error=True) + result = {} + for port_id in port_ids: + result[port_id] = None + if (port_id not in by_id or + by_id[port_id]['name'] not in intfs_on_bridge): + LOG.info(_LI("Port %(port_id)s not present in bridge " + "%(br_name)s"), + {'port_id': port_id, 'br_name': self.br_name}) + continue + pinfo = by_id[port_id] + if not self._check_ofport(port_id, pinfo): + continue + mac = pinfo['external_ids'].get('attached-mac') + result[port_id] = VifPort(pinfo['name'], pinfo['ofport'], + port_id, mac, self) + return result + + @staticmethod + def _check_ofport(port_id, port_info): + if port_info['ofport'] in [UNASSIGNED_OFPORT, INVALID_OFPORT]: + LOG.warn(_LW("ofport: %(ofport)s for VIF: %(vif)s is not a" + " positive integer"), + {'ofport': port_info['ofport'], 'vif': port_id}) + return False + return True + def get_vif_port_by_id(self, port_id): ports = self.ovsdb.db_find( 'Interface', ('external_ids', '=', {'iface-id': port_id}), @@ -413,10 +449,7 @@ class OVSBridge(BaseOVS): for port in ports: if self.br_name != self.get_bridge_for_iface(port['name']): continue - if port['ofport'] in [UNASSIGNED_OFPORT, INVALID_OFPORT]: - LOG.warn(_LW("ofport: %(ofport)s for VIF: %(vif)s is not a" - " positive integer"), - {'ofport': port['ofport'], 'vif': port_id}) + if not self._check_ofport(port_id, port): continue mac = port['external_ids'].get('attached-mac') return VifPort(port['name'], port['ofport'], port_id, mac, self) diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py index c07daadb121..60940e5b5b2 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py @@ -312,10 +312,17 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, def _restore_local_vlan_map(self): cur_ports = self.int_br.get_vif_ports() + port_info = self.int_br.db_list( + "Port", columns=["name", "other_config", "tag"]) + by_name = {x['name']: x for x in port_info} for port in cur_ports: - local_vlan_map = self.int_br.db_get_val("Port", port.port_name, - "other_config") - local_vlan = self.int_br.db_get_val("Port", port.port_name, "tag") + # if a port was deleted between get_vif_ports and db_lists, we + # will get a KeyError + try: + local_vlan_map = by_name[port.port_name]['other_config'] + local_vlan = by_name[port.port_name]['tag'] + except KeyError: + continue if not local_vlan: continue net_uuid = local_vlan_map.get('net_uuid') @@ -730,6 +737,9 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, port_other_config) def _bind_devices(self, need_binding_ports): + port_info = self.int_br.db_list( + "Port", columns=["name", "tag"]) + tags_by_name = {x['name']: x['tag'] for x in port_info} for port_detail in need_binding_ports: lvm = self.local_vlan_map.get(port_detail['network_id']) if not lvm: @@ -739,7 +749,7 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, port = port_detail['vif_port'] device = port_detail['device'] # Do not bind a port if it's already bound - cur_tag = self.int_br.db_get_val("Port", port.port_name, "tag") + cur_tag = tags_by_name.get(port.port_name) if cur_tag != lvm.vlan: self.int_br.set_db_attribute( "Port", port.port_name, "tag", lvm.vlan) @@ -1196,10 +1206,12 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, self.conf.host) except Exception as e: raise DeviceListRetrievalError(devices=devices, error=e) + vif_by_id = self.int_br.get_vifs_by_ids( + [vif['device'] for vif in devices_details_list]) for details in devices_details_list: device = details['device'] LOG.debug("Processing port: %s", device) - port = self.int_br.get_vif_port_by_id(device) + port = vif_by_id.get(device) if not port: # The port disappeared and cannot be processed LOG.info(_LI("Port %s was not found on the integration bridge " diff --git a/neutron/tests/functional/agent/test_ovs_lib.py b/neutron/tests/functional/agent/test_ovs_lib.py index f430481899b..d90e7fbfa25 100644 --- a/neutron/tests/functional/agent/test_ovs_lib.py +++ b/neutron/tests/functional/agent/test_ovs_lib.py @@ -209,6 +209,15 @@ class OVSBridgeTestCase(OVSBridgeTestBase): self.assertEqual(self.br.get_vif_port_by_id(vif.vif_id).vif_id, vif.vif_id) + def test_get_vifs_by_ids(self): + for i in range(2): + self.create_ovs_port() + vif_ports = [self.create_ovs_vif_port() for i in range(3)] + by_id = self.br.get_vifs_by_ids([v.vif_id for v in vif_ports]) + # convert to str for comparison of VifPorts + by_id = {vid: str(vport) for vid, vport in by_id.items()} + self.assertEqual({v.vif_id: str(v) for v in vif_ports}, by_id) + def test_delete_ports(self): # TODO(twilson) I intensely dislike the current delete_ports function # as the default behavior is really delete_vif_ports(), then it acts diff --git a/neutron/tests/unit/agent/common/test_ovs_lib.py b/neutron/tests/unit/agent/common/test_ovs_lib.py index 9e9c514dcd8..3f0b12b3b85 100644 --- a/neutron/tests/unit/agent/common/test_ovs_lib.py +++ b/neutron/tests/unit/agent/common/test_ovs_lib.py @@ -470,23 +470,22 @@ class OVS_Lib_Test(base.BaseTestCase): def _test_get_vif_ports(self, is_xen=False): pname = "tap99" ofport = 6 - ofport_data = self._encode_ovs_json(['ofport'], [[ofport]]) vif_id = uuidutils.generate_uuid() mac = "ca:fe:de:ad:be:ef" id_field = 'xs-vif-uuid' if is_xen else 'iface-id' external_ids = ('{"data":[[["map",[["attached-mac","%(mac)s"],' '["%(id_field)s","%(vif)s"],' - '["iface-status","active"]]]]],' - '"headings":["external_ids"]}' % { - 'mac': mac, 'vif': vif_id, 'id_field': id_field}) + '["iface-status","active"]]], ' + '"%(name)s", %(ofport)s]],' + '"headings":["external_ids", "name", "ofport"]}' % { + 'mac': mac, 'vif': vif_id, 'id_field': id_field, + 'name': pname, 'ofport': ofport}) # Each element is a tuple of (expected mock call, return_value) expected_calls_and_values = [ (self._vsctl_mock("list-ports", self.BR_NAME), "%s\n" % pname), - (self._vsctl_mock("--columns=external_ids", "list", - "Interface", pname), external_ids), - (self._vsctl_mock("--columns=ofport", "list", "Interface", pname), - ofport_data), + (self._vsctl_mock("--columns=name,external_ids,ofport", "list", + "Interface"), external_ids), ] if is_xen: expected_calls_and_values.append( @@ -724,6 +723,35 @@ class OVS_Lib_Test(base.BaseTestCase): with testtools.ExpectedException(Exception): self.br.get_local_port_mac() + def test_get_vifs_by_ids(self): + db_list_res = [ + {'name': 'qvo1', 'ofport': 1, + 'external_ids': {'iface-id': 'pid1', 'attached-mac': '11'}}, + {'name': 'qvo2', 'ofport': 2, + 'external_ids': {'iface-id': 'pid2', 'attached-mac': '22'}}, + {'name': 'qvo3', 'ofport': 3, + 'external_ids': {'iface-id': 'pid3', 'attached-mac': '33'}}, + {'name': 'qvo4', 'ofport': -1, + 'external_ids': {'iface-id': 'pid4', 'attached-mac': '44'}}, + ] + self.br.db_list = mock.Mock(return_value=db_list_res) + self.br.ovsdb = mock.Mock() + self.br.ovsdb.list_ports.return_value.execute.return_value = [ + 'qvo1', 'qvo2', 'qvo4'] + by_id = self.br.get_vifs_by_ids(['pid1', 'pid2', 'pid3', + 'pid4', 'pid5']) + # pid3 isn't on bridge and pid4 doesn't have a valid ofport and pid5 + # isn't present in the db + self.assertIsNone(by_id['pid3']) + self.assertIsNone(by_id['pid4']) + self.assertIsNone(by_id['pid5']) + self.assertEqual('pid1', by_id['pid1'].vif_id) + self.assertEqual('qvo1', by_id['pid1'].port_name) + self.assertEqual(1, by_id['pid1'].ofport) + self.assertEqual('pid2', by_id['pid2'].vif_id) + self.assertEqual('qvo2', by_id['pid2'].port_name) + self.assertEqual(2, by_id['pid2'].ofport) + def _test_get_vif_port_by_id(self, iface_id, data, br_name=None, extra_calls_and_values=None): headings = ['external_ids', 'name', 'ofport'] diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py index 61423751d28..d0a2a344811 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py @@ -114,6 +114,8 @@ class TestOvsNeutronAgent(object): cfg.CONF.set_default('quitting_rpc_timeout', 10, 'AGENT') cfg.CONF.set_default('prevent_arp_spoofing', False, 'AGENT') kwargs = self.mod_agent.create_agent_config_map(cfg.CONF) + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.db_list', + return_value=[]).start() with mock.patch.object(self.mod_agent.OVSNeutronAgent, 'setup_integration_br'),\ @@ -172,7 +174,10 @@ class TestOvsNeutronAgent(object): mock.patch.object(self.agent, 'provision_local_vlan') as \ provision_local_vlan: int_br.get_vif_ports.return_value = [port] - int_br.db_get_val.side_effect = [local_vlan_map, tag] + int_br.db_list.return_value = [{ + 'name': port.port_name, 'other_config': local_vlan_map, + 'tag': tag + }] self.agent._restore_local_vlan_map() if tag: self.assertTrue(provision_local_vlan.called) @@ -341,8 +346,8 @@ class TestOvsNeutronAgent(object): 'get_devices_details_list', return_value=[details]),\ mock.patch.object(self.agent.int_br, - 'get_vif_port_by_id', - return_value=port),\ + 'get_vifs_by_ids', + return_value={details['device']: port}),\ mock.patch.object(self.agent, func_name) as func: skip_devs, need_bound_devices = ( self.agent.treat_devices_added_or_updated([{}], False)) @@ -383,8 +388,8 @@ class TestOvsNeutronAgent(object): 'get_devices_details_list', return_value=[dev_mock]),\ mock.patch.object(self.agent.int_br, - 'get_vif_port_by_id', - return_value=None),\ + 'get_vifs_by_ids', + return_value={}),\ mock.patch.object(self.agent, 'treat_vif_port') as treat_vif_port: skip_devs = self.agent.treat_devices_added_or_updated([{}], False) @@ -410,8 +415,8 @@ class TestOvsNeutronAgent(object): 'get_devices_details_list', return_value=[fake_details_dict]),\ mock.patch.object(self.agent.int_br, - 'get_vif_port_by_id', - return_value=mock.MagicMock()),\ + 'get_vifs_by_ids', + return_value={'xxx': mock.MagicMock()}),\ mock.patch.object(self.agent, 'treat_vif_port') as treat_vif_port: skip_devs, need_bound_devices = ( @@ -449,6 +454,8 @@ class TestOvsNeutronAgent(object): self.agent, "treat_devices_added_or_updated", return_value=([], [])) as device_added_updated,\ + mock.patch.object(self.agent.int_br, "db_list", + return_value=[]),\ mock.patch.object(self.agent, "treat_devices_removed", return_value=False) as device_removed: @@ -1179,6 +1186,9 @@ class AncillaryBridgesTest(object): mock.patch('neutron.agent.common.ovs_lib.BaseOVS.' 'get_bridge_external_bridge_id', side_effect=pullup_side_effect),\ + mock.patch( + 'neutron.agent.common.ovs_lib.OVSBridge.' 'db_list', + return_value=[]),\ mock.patch( 'neutron.agent.common.ovs_lib.OVSBridge.' 'get_vif_ports', return_value=[]): @@ -1268,6 +1278,9 @@ class TestOvsDvrNeutronAgent(object): mock.patch('neutron.openstack.common.loopingcall.' 'FixedIntervalLoopingCall', new=MockFixedIntervalLoopingCall),\ + mock.patch( + 'neutron.agent.common.ovs_lib.OVSBridge.' 'db_list', + return_value=[]),\ mock.patch( 'neutron.agent.common.ovs_lib.OVSBridge.' 'get_vif_ports', return_value=[]): diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py index 6973842aab6..e0c8df7ef66 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py @@ -121,6 +121,7 @@ class TunnelTest(object): self.mock_int_bridge.add_patch_port.side_effect = ( lambda tap, peer: self.ovs_int_ofports[tap]) self.mock_int_bridge.get_vif_ports.return_value = [] + self.mock_int_bridge.db_list.return_value = [] self.mock_int_bridge.db_get_val.return_value = {} self.mock_map_tun_bridge = self.ovs_bridges[self.MAP_TUN_BRIDGE] @@ -208,6 +209,7 @@ class TunnelTest(object): ] self.mock_int_bridge_expected += [ mock.call.get_vif_ports(), + mock.call.db_list('Port', columns=['name', 'other_config', 'tag']) ] self.mock_tun_bridge_expected += [ @@ -246,7 +248,7 @@ class TunnelTest(object): def _verify_mock_call(self, mock_obj, expected): mock_obj.assert_has_calls(expected) - self.assertEqual(len(mock_obj.mock_calls), len(expected)) + self.assertEqual(expected, mock_obj.mock_calls) def _verify_mock_calls(self): self._verify_mock_call(self.mock_int_bridge_cls, @@ -599,6 +601,7 @@ class TunnelTestUseVethInterco(TunnelTest): ] self.mock_int_bridge_expected += [ mock.call.get_vif_ports(), + mock.call.db_list('Port', columns=['name', 'other_config', 'tag']) ] self.mock_tun_bridge_expected += [ mock.call.delete_flows(), From 8dd8a7d93564168b98fa2350eedf56acede42b0f Mon Sep 17 00:00:00 2001 From: "Sean M. Collins" Date: Tue, 30 Jun 2015 12:06:07 -0400 Subject: [PATCH 2/5] Remove bridge cleanup call Remove the bridge cleanup call to delete bridges, since we are seeing race conditions where bridges are deleted, then new interfaces are created and are attempting to plug into the bridge before it is recreated. Change-Id: I4ccc96566a5770384eacbbdc492bf09a514f5b31 Related-Bug: #1328546 --- .../ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py | 1 - 1 file changed, 1 deletion(-) diff --git a/neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py b/neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py index 66be308a29a..1e21db74c7a 100644 --- a/neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py @@ -948,7 +948,6 @@ class LinuxBridgeNeutronAgentRPC(service.Service): LOG.info(_LI("Port %s updated."), device) else: LOG.debug("Device %s not defined on plugin", device) - self.br_mgr.remove_empty_bridges() return resync def scan_devices(self, previous, sync): From cf8c9e40c8720036bd0c06bd8370f88a472e3e6f Mon Sep 17 00:00:00 2001 From: Fawad Khaliq Date: Tue, 30 Jun 2015 02:17:19 -0700 Subject: [PATCH 3/5] Update PLUMgrid plugin information README was quite oudated and created confusion among users. Updated the information after decomposition. Change-Id: I78bf8dec20ba2ceb644d4565035d29bbf53cb3b5 --- neutron/plugins/plumgrid/README | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/neutron/plugins/plumgrid/README b/neutron/plugins/plumgrid/README index e7118307d3e..5fc4050e4cb 100644 --- a/neutron/plugins/plumgrid/README +++ b/neutron/plugins/plumgrid/README @@ -1,8 +1,14 @@ -PLUMgrid Neutron Plugin for Virtual Network Infrastructure (VNI) +PLUMgrid Neutron Plugin +======================== -This plugin implements Neutron v2 APIs and helps configure -L2/L3 virtual networks consisting of PLUMgrid Platform. -Implements External Networks and Port Binding Extension +PLUMgrid Neutron Plugin for PLUMgrid Open Networking Suite -For more details on use please refer to: -http://wiki.openstack.org/PLUMgrid-Neutron +* Full plugin code is available at: + * https://github.com/stackforge/networking-plumgrid + +* PyPI package location: + * https://pypi.python.org/pypi/networking-plumgrid + +* For config, install and other details, please refer to + wiki page: + * http://wiki.openstack.org/PLUMgrid-Neutron From 49569327c20d8a10ba3d426833ff28d68b1b7a27 Mon Sep 17 00:00:00 2001 From: armando-migliaccio Date: Wed, 1 Jul 2015 12:00:14 -0700 Subject: [PATCH 4/5] Fix log traces induced by retry decorator Patch 4e77442d5 added a retry decorator to the API layer to catch DB deadlock errors. However, when they occur, the retried operation ends up being ineffective because the original body has been altered, which leads the notification and validation layers to barf exceptions due to unrecognized/unserializable elements. This ultimately results to an error reported to the user. To address this, let's make a deep copy of the request body, before we pass it down to the lower layers. This allows the decorator to work on a pristine copy of the body on every attempt. The performance impact for this should be negligible. Closes-bug: #1470615 Change-Id: I82a2a002612d28fa8f97b0afbd4f7ba1e8830377 --- neutron/api/v2/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/neutron/api/v2/base.py b/neutron/api/v2/base.py index d0f2aa8f156..48dea6bf6d0 100644 --- a/neutron/api/v2/base.py +++ b/neutron/api/v2/base.py @@ -391,7 +391,8 @@ class Controller(object): self._notifier.info(request.context, self._resource + '.create.start', body) - body = Controller.prepare_request_body(request.context, body, True, + body = Controller.prepare_request_body(request.context, + copy.deepcopy(body), True, self._resource, self._attr_info, allow_bulk=self._allow_bulk) action = self._plugin_handlers[self.CREATE] From f1771131a85a2fe633126f354364205554ef71d1 Mon Sep 17 00:00:00 2001 From: Kevin Benton Date: Wed, 1 Jul 2015 13:06:38 -0700 Subject: [PATCH 5/5] Change the half of the bridge name used for ports The code to generate the names of the patch ports was based on a chunk of the bridge name starting from the beginning. With the long suffix, this ended up excluding all of the random characters in the name. (e.g. br-int374623235 would create an interface br-in-patch-tun). This meant that if two tests using patch interfaces ran together, they would have a name collision and one would fail. This patch updates the patch port name generation to use the randomized back portion of the name. Change-Id: I172e0b2c0b53e8c7151bd92f0915773ea62c0c6a Closes-Bug: #1470637 --- neutron/tests/functional/agent/test_l2_ovs_agent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neutron/tests/functional/agent/test_l2_ovs_agent.py b/neutron/tests/functional/agent/test_l2_ovs_agent.py index 75614b20f3c..6deaab64e2e 100644 --- a/neutron/tests/functional/agent/test_l2_ovs_agent.py +++ b/neutron/tests/functional/agent/test_l2_ovs_agent.py @@ -60,8 +60,8 @@ class OVSAgentTestFramework(base.BaseOVSLinuxTestCase): self.br_tun = base.get_rand_name(n_const.DEVICE_NAME_MAX_LEN, prefix='br-tun') patch_name_len = n_const.DEVICE_NAME_MAX_LEN - len("-patch-tun") - self.patch_tun = "%s-patch-tun" % self.br_int[:patch_name_len] - self.patch_int = "%s-patch-int" % self.br_tun[:patch_name_len] + self.patch_tun = "%s-patch-tun" % self.br_int[patch_name_len:] + self.patch_int = "%s-patch-int" % self.br_tun[patch_name_len:] self.ovs = ovs_lib.BaseOVS() self.config = self._configure_agent() self.driver = interface.OVSInterfaceDriver(self.config)