Skip to content

Commit 7672b0e

Browse files
Dont raise RouterInterfaceNotFound on overlap check router ports
A corner case of the fix done in [1] could happend if, as a race scenario, parallel requests evaluate other ports that could be deleted during the process if they had already determined a overlapping, in that case a RouterInterfaceNotFound exception was raised and the request finished with that exception and a 404 status code. This patch removes the exception due to a port not found, because if the port is not found, the related subnet should not participate in the overlap evaluation, so it makes no sense to break the process for a port that no longer exists. It also improves the previous validation to perform the overlapping check, being performed only when we have at least more than one subnet, as the overlapping check with only one subnet did not make sense. Closes-Bug: #1998226 [1] https://review.opendev.org/c/openstack/neutron/+/859143 Change-Id: If4afe6f525c46f9cf7f02d8aae27dfc56144fd62 (cherry picked from commit 92efd8e)
1 parent 25dc4c0 commit 7672b0e

File tree

3 files changed

+51
-24
lines changed

3 files changed

+51
-24
lines changed

neutron/db/l3_db.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,10 +1025,15 @@ def _add_router_port(self, context, port_id, router, device_owner):
10251025
subnets_id.extend([fixed_ip['subnet_id']
10261026
for fixed_ip in port['fixed_ips']])
10271027
else:
1028-
raise l3_exc.RouterInterfaceNotFound(
1029-
router_id=router.id, port_id=rp.port_id)
1030-
1031-
if subnets_id:
1028+
# due to race conditions maybe the port under analysis is
1029+
# deleted, so instead returning a RouterInterfaceNotFound
1030+
# we continue the analysis avoiding that port
1031+
LOG.debug("Port %s could not be found, it might have been "
1032+
"deleted concurrently. Will not be checked for "
1033+
"an overlapping router interface.",
1034+
rp.port_id)
1035+
1036+
if len(subnets_id) > 1:
10321037
id_filter = {'id': subnets_id}
10331038
subnets = self._core_plugin.get_subnets(context.elevated(),
10341039
filters=id_filter)

neutron/tests/base.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,11 @@ def setup_rootwrap(self):
492492
root_helper_daemon=get_rootwrap_daemon_cmd())
493493

494494
def _simulate_concurrent_requests_process_and_raise(self, calls, args):
495+
self._simulate_concurrent_requests_process(calls, args,
496+
raise_on_exception=True)
495497

498+
def _simulate_concurrent_requests_process(self, calls, args,
499+
raise_on_exception=False):
496500
class SimpleThread(threading.Thread):
497501
def __init__(self, q):
498502
super(SimpleThread, self).__init__()
@@ -529,10 +533,16 @@ def get_exception(self):
529533
t.start()
530534
q.join()
531535

536+
threads_exceptions = []
532537
for t in threads:
533538
e = t.get_exception()
534539
if e:
535-
raise e
540+
if raise_on_exception:
541+
raise e
542+
else:
543+
threads_exceptions.append(e)
544+
545+
return threads_exceptions
536546

537547

538548
class PluginFixture(fixtures.Fixture):

neutron/tests/fullstack/test_l3_agent.py

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -270,25 +270,37 @@ def _is_filter_set(direction):
270270
def _test_concurrent_router_subnet_attachment_overlapping_cidr(self,
271271
ha=False):
272272
tenant_id = uuidutils.generate_uuid()
273-
subnet_cidr = '10.100.0.0/24'
274-
network1 = self.safe_client.create_network(
275-
tenant_id, name='foo-network1')
276-
subnet1 = self.safe_client.create_subnet(
277-
tenant_id, network1['id'], subnet_cidr)
278-
network2 = self.safe_client.create_network(
279-
tenant_id, name='foo-network2')
280-
subnet2 = self.safe_client.create_subnet(
281-
tenant_id, network2['id'], subnet_cidr)
273+
subnet_cidr = '10.200.0.0/24'
274+
# to have many port interactions where race conditions would happen
275+
# deleting ports meanwhile find operations to evaluate the overlapping
276+
subnets = 10
277+
278+
funcs = []
279+
args = []
282280
router = self.safe_client.create_router(tenant_id, ha=ha)
283281

284-
funcs = [self.safe_client.add_router_interface,
285-
self.safe_client.add_router_interface]
286-
args = [(router['id'], subnet1['id']), (router['id'], subnet2['id'])]
287-
self.assertRaises(
288-
exceptions.BadRequest,
289-
self._simulate_concurrent_requests_process_and_raise,
290-
funcs,
291-
args)
282+
for i in range(subnets):
283+
network_tmp = self.safe_client.create_network(
284+
tenant_id, name='foo-network' + str(i))
285+
subnet_tmp = self.safe_client.create_subnet(
286+
tenant_id, network_tmp['id'], subnet_cidr)
287+
funcs.append(self.safe_client.add_router_interface)
288+
args.append((router['id'], subnet_tmp['id']))
289+
290+
exception_requests = self._simulate_concurrent_requests_process(
291+
funcs, args)
292+
293+
if not all(type(e) == exceptions.BadRequest
294+
for e in exception_requests):
295+
self.fail('Unexpected exception adding interfaces to router from '
296+
'different subnets overlapping')
297+
298+
if not len(exception_requests) >= (subnets - 1):
299+
self.fail('If we have tried to associate %s subnets overlapping '
300+
'cidr to the router, we should have received at least '
301+
'%s or %s rejected requests, but we have only received '
302+
'%s', (str(subnets), str(subnets - 1), str(subnets),
303+
str(len(exception_requests))))
292304

293305

294306
class TestLegacyL3Agent(TestL3Agent):
@@ -441,7 +453,7 @@ def test_external_subnet_changed(self):
441453
def test_router_fip_qos_after_admin_state_down_up(self):
442454
self._router_fip_qos_after_admin_state_down_up()
443455

444-
def test_concurrent_router_subnet_attachment_overlapping_cidr_(self):
456+
def test_concurrent_router_subnet_attachment_overlapping_cidr(self):
445457
self._test_concurrent_router_subnet_attachment_overlapping_cidr()
446458

447459

@@ -601,6 +613,6 @@ def test_external_subnet_changed(self):
601613
def test_router_fip_qos_after_admin_state_down_up(self):
602614
self._router_fip_qos_after_admin_state_down_up(ha=True)
603615

604-
def test_concurrent_router_subnet_attachment_overlapping_cidr_(self):
616+
def test_concurrent_router_subnet_attachment_overlapping_cidr(self):
605617
self._test_concurrent_router_subnet_attachment_overlapping_cidr(
606618
ha=True)

0 commit comments

Comments
 (0)