Skip to content

Commit fb72afa

Browse files
authored
Merge pull request #17 from stackhpc/upstream/yoga-2022-12-12
Synchronise yoga with upstream
2 parents 33d9589 + 17a3140 commit fb72afa

File tree

25 files changed

+233
-146
lines changed

25 files changed

+233
-146
lines changed

neutron/agent/linux/keepalived.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ def build_config(self):
152152
LOG.warning("keepalived_use_no_track cfg option is True but "
153153
"keepalived on host seems to not support this "
154154
"option")
155+
# NOTE(mstinsky): neutron and keepalived are adding the same routes on
156+
# primary routers. With this we ensure that both are adding the routes
157+
# with the same procotol and prevent duplicated routes which result in
158+
# neutron exception for ip route commands.
159+
output += ' protocol static'
155160
return output
156161

157162

neutron/common/ovn/utils.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -633,8 +633,8 @@ def compute_address_pairs_diff(ovn_port, neutron_port):
633633

634634
def get_ovn_cms_options(chassis):
635635
"""Return the list of CMS options in a Chassis."""
636-
return [opt.strip() for opt in chassis.external_ids.get(
637-
constants.OVN_CMS_OPTIONS, '').split(',')]
636+
return [opt.strip() for opt in get_ovn_chassis_other_config(chassis).get(
637+
constants.OVN_CMS_OPTIONS, '').split(',')]
638638

639639

640640
def is_gateway_chassis(chassis):
@@ -823,3 +823,11 @@ def create_neutron_pg_drop():
823823
}]
824824

825825
OvsdbClientTransactCommand.run(command)
826+
827+
828+
def get_ovn_chassis_other_config(chassis):
829+
# NOTE(ralonsoh): LP#1990229 to be removed when min OVN version is 22.09
830+
try:
831+
return chassis.other_config
832+
except AttributeError:
833+
return chassis.external_ids

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/plugins/ml2/drivers/ovn/agent/neutron_agent.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ def as_dict(self):
8989
'configurations': {
9090
'chassis_name': self.chassis.name,
9191
'bridge-mappings':
92-
self.chassis.external_ids.get('ovn-bridge-mappings', '')},
92+
ovn_utils.get_ovn_chassis_other_config(self.chassis).get(
93+
'ovn-bridge-mappings', '')},
9394
'start_flag': True,
9495
'agent_type': self.agent_type,
9596
'id': self.agent_id,
@@ -141,9 +142,9 @@ class ControllerAgent(NeutronAgent):
141142

142143
@staticmethod # it is by default, but this makes pep8 happy
143144
def __new__(cls, chassis_private, driver):
144-
external_ids = cls.chassis_from_private(chassis_private).external_ids
145-
if ('enable-chassis-as-gw' in
146-
external_ids.get('ovn-cms-options', [])):
145+
_chassis = cls.chassis_from_private(chassis_private)
146+
other_config = ovn_utils.get_ovn_chassis_other_config(_chassis)
147+
if 'enable-chassis-as-gw' in other_config.get('ovn-cms-options', []):
147148
cls = ControllerGatewayAgent
148149
return super().__new__(cls)
149150

@@ -166,8 +167,9 @@ def description(self):
166167

167168
def update(self, chassis_private, clear_down=False):
168169
super().update(chassis_private, clear_down)
169-
external_ids = self.chassis_from_private(chassis_private).external_ids
170-
if 'enable-chassis-as-gw' in external_ids.get('ovn-cms-options', []):
170+
_chassis = self.chassis_from_private(chassis_private)
171+
other_config = ovn_utils.get_ovn_chassis_other_config(_chassis)
172+
if 'enable-chassis-as-gw' in other_config.get('ovn-cms-options', []):
171173
self.__class__ = ControllerGatewayAgent
172174

173175

@@ -176,9 +178,10 @@ class ControllerGatewayAgent(ControllerAgent):
176178

177179
def update(self, chassis_private, clear_down=False):
178180
super().update(chassis_private, clear_down)
179-
external_ids = self.chassis_from_private(chassis_private).external_ids
181+
_chassis = self.chassis_from_private(chassis_private)
182+
other_config = ovn_utils.get_ovn_chassis_other_config(_chassis)
180183
if ('enable-chassis-as-gw' not in
181-
external_ids.get('ovn-cms-options', [])):
184+
other_config.get('ovn-cms-options', [])):
182185
self.__class__ = ControllerAgent
183186

184187

neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ def sb_ovn(self, val):
179179
def get_supported_vif_types(self):
180180
vif_types = set()
181181
for ch in self.sb_ovn.chassis_list().execute(check_error=True):
182-
dp_type = ch.external_ids.get('datapath-type', '')
182+
other_config = ovn_utils.get_ovn_chassis_other_config(ch)
183+
dp_type = other_config.get('datapath-type', '')
183184
if dp_type == ovn_const.CHASSIS_DATAPATH_NETDEV:
184185
vif_types.add(portbindings.VIF_TYPE_VHOST_USER)
185186
else:
@@ -961,8 +962,9 @@ def bind_port(self, context):
961962
'agent': agent})
962963
return
963964
chassis = agent.chassis
964-
datapath_type = chassis.external_ids.get('datapath-type', '')
965-
iface_types = chassis.external_ids.get('iface-types', '')
965+
other_config = ovn_utils.get_ovn_chassis_other_config(chassis)
966+
datapath_type = other_config.get('datapath-type', '')
967+
iface_types = other_config.get('iface-types', '')
966968
iface_types = iface_types.split(',') if iface_types else []
967969
chassis_physnets = self.sb_ovn._get_chassis_physnets(chassis)
968970
for segment_to_bind in context.segments_to_bind:

neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/extensions/placement.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ def _parse_ovn_cms_options(chassis):
4242

4343

4444
def _parse_bridge_mappings(chassis):
45-
bridge_mappings = chassis.external_ids.get('ovn-bridge-mappings', '')
45+
other_config = ovn_utils.get_ovn_chassis_other_config(chassis)
46+
bridge_mappings = other_config.get('ovn-bridge-mappings', '')
4647
bridge_mappings = helpers.parse_mappings(bridge_mappings.split(','),
4748
unique_values=False)
4849
return {k: [v] for k, v in bridge_mappings.items()}

neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/impl_idl_ovn.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,8 @@ def from_worker(cls, worker_class, driver=None):
830830
return cls(conn)
831831

832832
def _get_chassis_physnets(self, chassis):
833-
bridge_mappings = chassis.external_ids.get('ovn-bridge-mappings', '')
833+
other_config = utils.get_ovn_chassis_other_config(chassis)
834+
bridge_mappings = other_config.get('ovn-bridge-mappings', '')
834835
mapping_dict = helpers.parse_mappings(bridge_mappings.split(','))
835836
return list(mapping_dict.keys())
836837

@@ -848,7 +849,8 @@ def get_gateway_chassis_from_cms_options(self, name_only=True):
848849
return [ch.name if name_only else ch
849850
for ch in self.chassis_list().execute(check_error=True)
850851
if ovn_const.CMS_OPT_CHASSIS_AS_GW in
851-
ch.external_ids.get(ovn_const.OVN_CMS_OPTIONS, '').split(',')]
852+
utils.get_ovn_chassis_other_config(ch).get(
853+
ovn_const.OVN_CMS_OPTIONS, '').split(',')]
852854

853855
def get_chassis_and_physnets(self):
854856
chassis_info_dict = {}
@@ -867,7 +869,7 @@ def get_chassis_by_card_serial_from_cms_options(self,
867869
if ('{}={}'
868870
.format(ovn_const.CMS_OPT_CARD_SERIAL_NUMBER,
869871
card_serial_number)
870-
in ch.external_ids.get(
872+
in utils.get_ovn_chassis_other_config(ch).get(
871873
ovn_const.OVN_CMS_OPTIONS, '').split(',')):
872874
return ch
873875
msg = _('Chassis with %s %s %s does not exist'

neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovsdb_monitor.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,21 @@ def handle_ha_chassis_group_changes(self, event, row, old):
172172
def match_fn(self, event, row, old):
173173
if event != self.ROW_UPDATE:
174174
return True
175-
# NOTE(lucasgomes): If the external_ids column wasn't updated
176-
# (meaning, Chassis "gateway" status didn't change) just returns
177-
if not hasattr(old, 'external_ids') and event == self.ROW_UPDATE:
175+
176+
# NOTE(ralonsoh): LP#1990229 to be removed when min OVN version is
177+
# 22.09
178+
other_config = ('other_config' if hasattr(row, 'other_config') else
179+
'external_ids')
180+
# NOTE(lucasgomes): If the other_config/external_ids column wasn't
181+
# updated (meaning, Chassis "gateway" status didn't change) just
182+
# returns
183+
if not hasattr(old, other_config) and event == self.ROW_UPDATE:
178184
return False
179-
if (old.external_ids.get('ovn-bridge-mappings') !=
180-
row.external_ids.get('ovn-bridge-mappings')):
185+
old_br_mappings = utils.get_ovn_chassis_other_config(old).get(
186+
'ovn-bridge-mappings')
187+
new_br_mappings = utils.get_ovn_chassis_other_config(row).get(
188+
'ovn-bridge-mappings')
189+
if old_br_mappings != new_br_mappings:
181190
return True
182191
# Check if either the Gateway status or Availability Zones has
183192
# changed in the Chassis
@@ -192,8 +201,9 @@ def match_fn(self, event, row, old):
192201
def run(self, event, row, old):
193202
host = row.hostname
194203
phy_nets = []
204+
new_other_config = utils.get_ovn_chassis_other_config(row)
195205
if event != self.ROW_DELETE:
196-
bridge_mappings = row.external_ids.get('ovn-bridge-mappings', '')
206+
bridge_mappings = new_other_config.get('ovn-bridge-mappings', '')
197207
mapping_dict = helpers.parse_mappings(bridge_mappings.split(','))
198208
phy_nets = list(mapping_dict)
199209

@@ -208,9 +218,10 @@ def run(self, event, row, old):
208218
if event == self.ROW_DELETE:
209219
kwargs['event_from_chassis'] = row.name
210220
elif event == self.ROW_UPDATE:
211-
old_mappings = old.external_ids.get('ovn-bridge-mappings',
221+
old_other_config = utils.get_ovn_chassis_other_config(old)
222+
old_mappings = old_other_config.get('ovn-bridge-mappings',
212223
set()) or set()
213-
new_mappings = row.external_ids.get('ovn-bridge-mappings',
224+
new_mappings = new_other_config.get('ovn-bridge-mappings',
214225
set()) or set()
215226
if old_mappings:
216227
old_mappings = set(old_mappings.split(','))
@@ -339,11 +350,17 @@ class ChassisAgentTypeChangeEvent(ChassisEvent):
339350
events = (BaseEvent.ROW_UPDATE,)
340351

341352
def match_fn(self, event, row, old=None):
342-
if not getattr(old, 'external_ids', False):
353+
# NOTE(ralonsoh): LP#1990229 to be removed when min OVN version is
354+
# 22.09
355+
other_config = ('other_config' if hasattr(row, 'other_config') else
356+
'external_ids')
357+
if not getattr(old, other_config, False):
343358
return False
344-
agent_type_change = n_agent.NeutronAgent.chassis_from_private(
345-
row).external_ids.get('ovn-cms-options', []) != (
346-
old.external_ids.get('ovn-cms-options', []))
359+
chassis = n_agent.NeutronAgent.chassis_from_private(row)
360+
new_other_config = utils.get_ovn_chassis_other_config(chassis)
361+
old_other_config = utils.get_ovn_chassis_other_config(old)
362+
agent_type_change = new_other_config.get('ovn-cms-options', []) != (
363+
old_other_config.get('ovn-cms-options', []))
347364
return agent_type_change
348365

349366
def run(self, event, row, old):

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)