Skip to content

Commit 98677bf

Browse files
authored
Merge pull request #126 from stackhpc/upstream/2023.1-2024-03-04
Synchronise 2023.1 with upstream
2 parents fc170a5 + c162ea2 commit 98677bf

File tree

13 files changed

+135
-84
lines changed

13 files changed

+135
-84
lines changed

doc/source/admin/config-ipv6.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -686,18 +686,19 @@ First, create a network and IPv6 subnet:
686686
+---------------------------+--------------------------------------+
687687
688688
$ openstack subnet create --ip-version 6 --ipv6-ra-mode slaac \
689-
--ipv6-address-mode slaac --use-default-subnet-pool \
689+
--ipv6-address-mode slaac --use-prefix-delegation \
690690
--network ipv6-pd ipv6-pd-1
691691
+------------------------+--------------------------------------+
692692
| Field | Value |
693693
+------------------------+--------------------------------------+
694-
| allocation_pools | ::2-::ffff:ffff:ffff:ffff |
694+
| allocation_pools | ::1-::ffff:ffff:ffff:ffff |
695695
| cidr | ::/64 |
696696
| created_at | 2017-01-25T19:31:53Z |
697697
| description | |
698698
| dns_nameservers | |
699+
| dns_publish_fixed_ip | None |
699700
| enable_dhcp | True |
700-
| gateway_ip | ::1 |
701+
| gateway_ip | :: |
701702
| headers | |
702703
| host_routes | |
703704
| id | 1319510d-c92c-4532-bf5d-8bcf3da761a1 |
@@ -710,9 +711,8 @@ First, create a network and IPv6 subnet:
710711
| revision_number | 2 |
711712
| service_types | |
712713
| subnetpool_id | prefix_delegation |
713-
| tags | [] |
714+
| tags | |
714715
| updated_at | 2017-01-25T19:31:53Z |
715-
| use_default_subnetpool | True |
716716
+------------------------+--------------------------------------+
717717
718718
The subnet is initially created with a temporary CIDR before one can be

neutron/agent/metadata/driver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ def spawn_monitored_metadata_proxy(cls, monitor, ns_name, port, conf,
270270
ns_name=ns_name,
271271
callback=callback)
272272
try:
273-
pm.enable()
273+
pm.enable(ensure_active=True)
274274
except exceptions.ProcessExecutionError as exec_err:
275275
LOG.error("Encountered process execution error %(err)s while "
276276
"starting process in namespace %(ns)s",

neutron/agent/ovn/metadata/driver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def spawn_monitored_metadata_proxy(cls, monitor, ns_name, port, conf,
181181
ns_name=ns_name,
182182
callback=callback)
183183
try:
184-
pm.enable()
184+
pm.enable(ensure_active=True)
185185
except exceptions.ProcessExecutionError as exec_err:
186186
LOG.error("Encountered process execution error %(err)s while "
187187
"starting process in namespace %(ns)s",

neutron/db/db_base_plugin_v2.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ def _validate_ip_version(self, ip_version, addr, name):
595595
"the ip_version '%(ip_version)s'") % data
596596
raise exc.InvalidInput(error_message=msg)
597597

598-
def _validate_subnet(self, context, s, cur_subnet=None):
598+
def _validate_subnet(self, context, s, cur_subnet=None, is_pd=False):
599599
"""Validate a subnet spec."""
600600

601601
# This method will validate attributes which may change during
@@ -613,6 +613,7 @@ def _validate_subnet(self, context, s, cur_subnet=None):
613613
has_cidr = False
614614
if validators.is_attr_set(s.get('cidr')):
615615
self._validate_ip_version(ip_ver, s['cidr'], 'cidr')
616+
net = netaddr.IPNetwork(s['cidr'])
616617
has_cidr = True
617618

618619
# TODO(watanabe.isao): After we found a way to avoid the re-sync
@@ -621,15 +622,21 @@ def _validate_subnet(self, context, s, cur_subnet=None):
621622
dhcp_was_enabled = cur_subnet.enable_dhcp
622623
else:
623624
dhcp_was_enabled = False
625+
# A subnet cidr of '::' is invalid, unless the caller has
626+
# indicated they are doing Prefix Delegation,
627+
# see https://bugs.launchpad.net/neutron/+bug/2028159
628+
if (has_cidr and ip_ver == constants.IP_VERSION_6 and
629+
net.network == netaddr.IPAddress('::') and not
630+
is_pd):
631+
error_message = _("IPv6 subnet '::' is not supported")
632+
raise exc.InvalidInput(error_message=error_message)
624633
if has_cidr and s.get('enable_dhcp') and not dhcp_was_enabled:
625-
subnet_prefixlen = netaddr.IPNetwork(s['cidr']).prefixlen
626634
error_message = _("Subnet has a prefix length that is "
627635
"incompatible with DHCP service enabled")
628-
if ((ip_ver == 4 and subnet_prefixlen > 30) or
629-
(ip_ver == 6 and subnet_prefixlen > 126)):
636+
if ((ip_ver == 4 and net.prefixlen > 30) or
637+
(ip_ver == 6 and net.prefixlen > 126)):
630638
raise exc.InvalidInput(error_message=error_message)
631639

632-
net = netaddr.IPNetwork(s['cidr'])
633640
if net.is_multicast():
634641
error_message = _("Multicast IP subnet is not supported "
635642
"if enable_dhcp is True")
@@ -874,9 +881,11 @@ def _create_subnet_precommit(self, context, subnet):
874881
raise exc.BadRequest(resource='subnets', msg=msg)
875882

876883
validate = True
884+
is_pd = False
877885
if subnetpool_id:
878886
self.ipam.validate_pools_with_subnetpool(s)
879887
if subnetpool_id == constants.IPV6_PD_POOL_ID:
888+
is_pd = True
880889
if has_cidr:
881890
# We do not currently support requesting a specific
882891
# cidr with IPv6 prefix delegation. Set the subnetpool_id
@@ -894,7 +903,7 @@ def _create_subnet_precommit(self, context, subnet):
894903
raise exc.BadRequest(resource='subnets', msg=msg)
895904

896905
if validate:
897-
self._validate_subnet(context, s)
906+
self._validate_subnet(context, s, is_pd=is_pd)
898907

899908
with db_api.CONTEXT_WRITER.using(context):
900909
network = self._get_network(context,
@@ -950,7 +959,8 @@ def _update_subnet_precommit(self, context, id, subnet):
950959
# Fill 'network_id' field with the current value since this is expected
951960
# by _validate_segment() in ipam_pluggable_backend.
952961
s['network_id'] = subnet_obj.network_id
953-
self._validate_subnet(context, s, cur_subnet=subnet_obj)
962+
is_pd = s['subnetpool_id'] == constants.IPV6_PD_POOL_ID
963+
self._validate_subnet(context, s, cur_subnet=subnet_obj, is_pd=is_pd)
954964
db_pools = [netaddr.IPRange(p.start, p.end)
955965
for p in subnet_obj.allocation_pools]
956966

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

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,11 +1486,13 @@ def get_candidates_for_scheduling(self, physnet, cms=None,
14861486
"""Return chassis for scheduling gateway router.
14871487
14881488
Criteria for selecting chassis as candidates
1489-
1) chassis from cms with proper bridge mappings
1490-
2) if no chassis is available from 1) then,
1491-
select chassis with proper bridge mappings
1492-
3) Filter the available chassis accordingly to the routers
1489+
1) Chassis from cms with proper bridge mappings only (that means these
1490+
gateway chassis with the requested physical network).
1491+
2) Filter the available chassis accordingly to the routers
14931492
availability zone hints (if present)
1493+
1494+
If the logical router port belongs to a tunnelled network, there won't
1495+
be any candidate.
14941496
"""
14951497
# TODO(lucasagomes): Simplify the logic here, the CMS option has
14961498
# been introduced long ago and by now all gateway chassis should
@@ -1499,15 +1501,13 @@ def get_candidates_for_scheduling(self, physnet, cms=None,
14991501
cms = cms or self._sb_idl.get_gateway_chassis_from_cms_options()
15001502
chassis_physnets = (chassis_physnets or
15011503
self._sb_idl.get_chassis_and_physnets())
1502-
cms_bmaps = []
1503-
bmaps = []
1504+
candidates = set()
15041505
for chassis, physnets in chassis_physnets.items():
1505-
if physnet and physnet in physnets:
1506-
if chassis in cms:
1507-
cms_bmaps.append(chassis)
1508-
else:
1509-
bmaps.append(chassis)
1510-
candidates = cms_bmaps or bmaps or cms
1506+
if (physnet and
1507+
physnet in physnets and
1508+
chassis in cms):
1509+
candidates.add(chassis)
1510+
candidates = list(candidates)
15111511

15121512
# Filter for availability zones
15131513
if availability_zone_hints:
@@ -1518,11 +1518,8 @@ def get_candidates_for_scheduling(self, physnet, cms=None,
15181518
if az in utils.get_chassis_availability_zones(
15191519
self._sb_idl.lookup('Chassis', ch, None))]
15201520

1521-
if not cms_bmaps:
1522-
LOG.debug("No eligible chassis with external connectivity"
1523-
" through ovn-cms-options for %s", physnet)
1524-
LOG.debug("Chassis candidates for scheduling gateway router ports: %s",
1525-
candidates)
1521+
LOG.debug('Chassis candidates for scheduling gateway router ports '
1522+
'for "%s" physical network: %s', physnet, candidates)
15261523
return candidates
15271524

15281525
def _get_physnet(self, network):

neutron/privileged/agent/linux/ip_lib.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,10 @@ def set_link_flags(device, namespace, flags):
400400
_run_iproute_link("set", device, namespace, flags=new_flags)
401401

402402

403+
@tenacity.retry(
404+
retry=tenacity.retry_if_exception_type(NetworkInterfaceNotFound),
405+
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
406+
stop=tenacity.stop_after_delay(3), reraise=True)
403407
@privileged.link_cmd.entrypoint
404408
def set_link_attribute(device, namespace, **attributes):
405409
_run_iproute_link("set", device, namespace, **attributes)
@@ -430,7 +434,8 @@ def set_link_bridge_master(device, bridge, namespace=None):
430434

431435
@tenacity.retry(
432436
retry=tenacity.retry_if_exception_type(
433-
netlink_exceptions.NetlinkDumpInterrupted),
437+
(netlink_exceptions.NetlinkDumpInterrupted,
438+
NetworkInterfaceNotFound)),
434439
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
435440
stop=tenacity.stop_after_delay(8),
436441
reraise=True)

neutron/tests/functional/services/ovn_l3/test_plugin.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@
3232

3333

3434
class TestRouter(base.TestOVNFunctionalBase):
35-
def setUp(self):
36-
super(TestRouter, self).setUp()
35+
def setUp(self, **kwargs):
36+
super().setUp(**kwargs)
3737
self.chassis1 = self.add_fake_chassis(
38-
'ovs-host1', physical_nets=['physnet1', 'physnet3'])
38+
'ovs-host1', physical_nets=['physnet1', 'physnet3'],
39+
enable_chassis_as_gw=True, azs=[])
3940
self.chassis2 = self.add_fake_chassis(
40-
'ovs-host2', physical_nets=['physnet2', 'physnet3'])
41+
'ovs-host2', physical_nets=['physnet2', 'physnet3'],
42+
enable_chassis_as_gw=True, azs=[])
4143
self.cr_lrp_pb_event = events.WaitForCrLrpPortBindingEvent()
4244
self.sb_api.idl.notify_handler.watch_event(self.cr_lrp_pb_event)
4345

@@ -95,12 +97,14 @@ def test_gateway_chassis_on_router_gateway_port(self):
9597
self.assertIn(rc, expected)
9698

9799
def _check_gateway_chassis_candidates(self, candidates,
98-
router_az_hints=None):
100+
router_az_hints=None,
101+
physnet='physnet1'):
99102
# In this test, fake_select() is called once from _create_router()
100103
# and later from schedule_unhosted_gateways()
101104
ovn_client = self.l3_plugin._ovn_client
105+
net_type = 'vlan' if physnet else 'geneve'
102106
ext1 = self._create_ext_network(
103-
'ext1', 'vlan', 'physnet1', 1, "10.0.0.1", "10.0.0.0/24")
107+
'ext1', net_type, physnet, 1, "10.0.0.1", "10.0.0.0/24")
104108
# mock select function and check if it is called with expected
105109
# candidates.
106110

@@ -131,12 +135,11 @@ def fake_select(*args, **kwargs):
131135

132136
def test_gateway_chassis_with_cms_and_bridge_mappings(self):
133137
# Both chassis1 and chassis3 are having proper bridge mappings,
134-
# but only chassis3 is having enable-chassis-as-gw.
135-
# Test if chassis3 is selected as candidate or not.
138+
# but only chassis1 is having enable-chassis-as-gw.
139+
# Test if chassis1 is selected as candidate or not.
136140
self.chassis3 = self.add_fake_chassis(
137-
'ovs-host3', physical_nets=['physnet1'],
138-
other_config={'ovn-cms-options': 'enable-chassis-as-gw'})
139-
self._check_gateway_chassis_candidates([self.chassis3])
141+
'ovs-host3', physical_nets=['physnet1'], azs=[])
142+
self._check_gateway_chassis_candidates([self.chassis1])
140143

141144
def test_gateway_chassis_with_cms_and_no_bridge_mappings(self):
142145
# chassis1 is having proper bridge mappings.
@@ -170,12 +173,10 @@ def test_gateway_chassis_with_cms_and_azs(self):
170173
# Test if chassis3 is selected as candidate or not.
171174
self.chassis3 = self.add_fake_chassis(
172175
'ovs-host3', physical_nets=['physnet1'],
173-
other_config={'ovn-cms-options': 'enable-chassis-as-gw'},
174-
azs=['ovn'])
176+
azs=['ovn'], enable_chassis_as_gw=True)
175177
self.chassis4 = self.add_fake_chassis(
176178
'ovs-host4', physical_nets=['physnet1'],
177-
other_config={'ovn-cms-options': 'enable-chassis-as-gw'},
178-
azs=['ovn2'])
179+
azs=['ovn2'], enable_chassis_as_gw=True)
179180
self._check_gateway_chassis_candidates([self.chassis3],
180181
router_az_hints=['ovn'])
181182

@@ -185,11 +186,9 @@ def test_gateway_chassis_with_cms_and_not_match_azs(self):
185186
# AvailabilityZoneNotFound. after create will delete if.
186187
# add chassis4 is having azs [ovn2], not match routers az_hints [ovn]
187188
self.chassis3 = self.add_fake_chassis(
188-
'ovs-host3', physical_nets=['physnet1'],
189-
other_config={'ovn-cms-options': 'enable-chassis-as-gw'})
189+
'ovs-host3', physical_nets=['physnet1'], enable_chassis_as_gw=True)
190190
self.chassis4 = self.add_fake_chassis(
191-
'ovs-host4', physical_nets=['physnet1'],
192-
other_config={'ovn-cms-options': 'enable-chassis-as-gw'},
191+
'ovs-host4', physical_nets=['physnet1'], enable_chassis_as_gw=True,
193192
azs=['ovn2'])
194193
ovn_client = self.l3_plugin._ovn_client
195194
ext1 = self._create_ext_network(
@@ -217,6 +216,11 @@ def test_gateway_chassis_with_bridge_mappings_and_no_cms(self):
217216
# Test if chassis1 is selected as candidate or not.
218217
self._check_gateway_chassis_candidates([self.chassis1])
219218

219+
def test_gateway_chassis_no_physnet_tunnelled_network(self):
220+
# The GW network is tunnelled, no physnet defined --> no possible
221+
# candidates.
222+
self._check_gateway_chassis_candidates([], physnet=None)
223+
220224
def _l3_ha_supported(self):
221225
# If the Gateway_Chassis table exists in SB database, then it
222226
# means that L3 HA is supported.

neutron/tests/unit/agent/dhcp/test_agent.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ def test_dhcp_ready_ports_updates_after_enable_dhcp(self, *args):
658658
'IpAddrCommand.wait_until_address_ready') as mock_wait:
659659
mock_wait.return_value = True
660660
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
661+
dhcp.update_isolated_metadata_proxy = mock.Mock()
661662
self.assertEqual(set(), dhcp.dhcp_ready_ports)
662663
dhcp.configure_dhcp_for_network(fake_network)
663664
self.assertEqual({fake_port1.id}, dhcp.dhcp_ready_ports)
@@ -854,7 +855,7 @@ def _enable_dhcp_helper(self, network, enable_isolated_metadata=False,
854855
is_ovn_network):
855856
process_instance.assert_has_calls([
856857
mock.call.disable(sig=str(int(signal.SIGTERM))),
857-
mock.call.enable()])
858+
mock.call.enable(ensure_active=True)])
858859
else:
859860
process_instance.assert_has_calls([
860861
mock.call.disable(sig=str(int(signal.SIGTERM)))])

neutron/tests/unit/agent/metadata/test_driver.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,12 @@ def _test_spawn_metadata_proxy(self, dad_failed=False):
171171
'IpAddrCommand.wait_until_address_ready') as mock_wait,\
172172
mock.patch(
173173
'neutron.agent.linux.ip_lib.'
174-
'delete_ip_address') as mock_del:
174+
'delete_ip_address') as mock_del,\
175+
mock.patch(
176+
'neutron.agent.linux.external_process.'
177+
'ProcessManager.active',
178+
new_callable=mock.PropertyMock,
179+
side_effect=[False, True]):
175180
agent = l3_agent.L3NATAgent('localhost')
176181
agent.process_monitor = mock.Mock()
177182
cfg_file = os.path.join(

neutron/tests/unit/agent/ovn/metadata/test_driver.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,12 @@ def test_spawn_metadata_proxy(self):
7474
return_value=test_utils.FakeUser(self.EUNAME)),\
7575
mock.patch('grp.getgrnam',
7676
return_value=test_utils.FakeGroup(self.EGNAME)),\
77-
mock.patch('os.makedirs'):
77+
mock.patch('os.makedirs'),\
78+
mock.patch(
79+
'neutron.agent.linux.external_process.'
80+
'ProcessManager.active',
81+
new_callable=mock.PropertyMock,
82+
side_effect=[False, True]):
7883
cfg_file = os.path.join(
7984
metadata_driver.HaproxyConfigurator.get_config_path(
8085
cfg.CONF.state_path),

0 commit comments

Comments
 (0)