Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions doc/source/admin/config-ipv6.rst
Original file line number Diff line number Diff line change
Expand Up @@ -686,18 +686,19 @@ First, create a network and IPv6 subnet:
+---------------------------+--------------------------------------+

$ openstack subnet create --ip-version 6 --ipv6-ra-mode slaac \
--ipv6-address-mode slaac --use-default-subnet-pool \
--ipv6-address-mode slaac --use-prefix-delegation \
--network ipv6-pd ipv6-pd-1
+------------------------+--------------------------------------+
| Field | Value |
+------------------------+--------------------------------------+
| allocation_pools | ::2-::ffff:ffff:ffff:ffff |
| allocation_pools | ::1-::ffff:ffff:ffff:ffff |
| cidr | ::/64 |
| created_at | 2017-01-25T19:31:53Z |
| description | |
| dns_nameservers | |
| dns_publish_fixed_ip | None |
| enable_dhcp | True |
| gateway_ip | ::1 |
| gateway_ip | :: |
| headers | |
| host_routes | |
| id | 1319510d-c92c-4532-bf5d-8bcf3da761a1 |
Expand All @@ -710,9 +711,8 @@ First, create a network and IPv6 subnet:
| revision_number | 2 |
| service_types | |
| subnetpool_id | prefix_delegation |
| tags | [] |
| tags | |
| updated_at | 2017-01-25T19:31:53Z |
| use_default_subnetpool | True |
+------------------------+--------------------------------------+

The subnet is initially created with a temporary CIDR before one can be
Expand Down
2 changes: 1 addition & 1 deletion neutron/agent/metadata/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ def spawn_monitored_metadata_proxy(cls, monitor, ns_name, port, conf,
ns_name=ns_name,
callback=callback)
try:
pm.enable()
pm.enable(ensure_active=True)
except exceptions.ProcessExecutionError as exec_err:
LOG.error("Encountered process execution error %(err)s while "
"starting process in namespace %(ns)s",
Expand Down
2 changes: 1 addition & 1 deletion neutron/agent/ovn/metadata/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def spawn_monitored_metadata_proxy(cls, monitor, ns_name, port, conf,
ns_name=ns_name,
callback=callback)
try:
pm.enable()
pm.enable(ensure_active=True)
except exceptions.ProcessExecutionError as exec_err:
LOG.error("Encountered process execution error %(err)s while "
"starting process in namespace %(ns)s",
Expand Down
24 changes: 17 additions & 7 deletions neutron/db/db_base_plugin_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ def _validate_ip_version(self, ip_version, addr, name):
"the ip_version '%(ip_version)s'") % data
raise exc.InvalidInput(error_message=msg)

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

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

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

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

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

if validate:
self._validate_subnet(context, s)
self._validate_subnet(context, s, is_pd=is_pd)

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

Expand Down
31 changes: 14 additions & 17 deletions neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1486,11 +1486,13 @@ def get_candidates_for_scheduling(self, physnet, cms=None,
"""Return chassis for scheduling gateway router.

Criteria for selecting chassis as candidates
1) chassis from cms with proper bridge mappings
2) if no chassis is available from 1) then,
select chassis with proper bridge mappings
3) Filter the available chassis accordingly to the routers
1) Chassis from cms with proper bridge mappings only (that means these
gateway chassis with the requested physical network).
2) Filter the available chassis accordingly to the routers
availability zone hints (if present)

If the logical router port belongs to a tunnelled network, there won't
be any candidate.
"""
# TODO(lucasagomes): Simplify the logic here, the CMS option has
# been introduced long ago and by now all gateway chassis should
Expand All @@ -1499,15 +1501,13 @@ def get_candidates_for_scheduling(self, physnet, cms=None,
cms = cms or self._sb_idl.get_gateway_chassis_from_cms_options()
chassis_physnets = (chassis_physnets or
self._sb_idl.get_chassis_and_physnets())
cms_bmaps = []
bmaps = []
candidates = set()
for chassis, physnets in chassis_physnets.items():
if physnet and physnet in physnets:
if chassis in cms:
cms_bmaps.append(chassis)
else:
bmaps.append(chassis)
candidates = cms_bmaps or bmaps or cms
if (physnet and
physnet in physnets and
chassis in cms):
candidates.add(chassis)
candidates = list(candidates)

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

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

def _get_physnet(self, network):
Expand Down
7 changes: 6 additions & 1 deletion neutron/privileged/agent/linux/ip_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,10 @@ def set_link_flags(device, namespace, flags):
_run_iproute_link("set", device, namespace, flags=new_flags)


@tenacity.retry(
retry=tenacity.retry_if_exception_type(NetworkInterfaceNotFound),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(3), reraise=True)
@privileged.link_cmd.entrypoint
def set_link_attribute(device, namespace, **attributes):
_run_iproute_link("set", device, namespace, **attributes)
Expand Down Expand Up @@ -430,7 +434,8 @@ def set_link_bridge_master(device, bridge, namespace=None):

@tenacity.retry(
retry=tenacity.retry_if_exception_type(
netlink_exceptions.NetlinkDumpInterrupted),
(netlink_exceptions.NetlinkDumpInterrupted,
NetworkInterfaceNotFound)),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(8),
reraise=True)
Expand Down
42 changes: 23 additions & 19 deletions neutron/tests/functional/services/ovn_l3/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@


class TestRouter(base.TestOVNFunctionalBase):
def setUp(self):
super(TestRouter, self).setUp()
def setUp(self, **kwargs):
super().setUp(**kwargs)
self.chassis1 = self.add_fake_chassis(
'ovs-host1', physical_nets=['physnet1', 'physnet3'])
'ovs-host1', physical_nets=['physnet1', 'physnet3'],
enable_chassis_as_gw=True, azs=[])
self.chassis2 = self.add_fake_chassis(
'ovs-host2', physical_nets=['physnet2', 'physnet3'])
'ovs-host2', physical_nets=['physnet2', 'physnet3'],
enable_chassis_as_gw=True, azs=[])
self.cr_lrp_pb_event = events.WaitForCrLrpPortBindingEvent()
self.sb_api.idl.notify_handler.watch_event(self.cr_lrp_pb_event)

Expand Down Expand Up @@ -95,12 +97,14 @@ def test_gateway_chassis_on_router_gateway_port(self):
self.assertIn(rc, expected)

def _check_gateway_chassis_candidates(self, candidates,
router_az_hints=None):
router_az_hints=None,
physnet='physnet1'):
# In this test, fake_select() is called once from _create_router()
# and later from schedule_unhosted_gateways()
ovn_client = self.l3_plugin._ovn_client
net_type = 'vlan' if physnet else 'geneve'
ext1 = self._create_ext_network(
'ext1', 'vlan', 'physnet1', 1, "10.0.0.1", "10.0.0.0/24")
'ext1', net_type, physnet, 1, "10.0.0.1", "10.0.0.0/24")
# mock select function and check if it is called with expected
# candidates.

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

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

def test_gateway_chassis_with_cms_and_no_bridge_mappings(self):
# chassis1 is having proper bridge mappings.
Expand Down Expand Up @@ -170,12 +173,10 @@ def test_gateway_chassis_with_cms_and_azs(self):
# Test if chassis3 is selected as candidate or not.
self.chassis3 = self.add_fake_chassis(
'ovs-host3', physical_nets=['physnet1'],
other_config={'ovn-cms-options': 'enable-chassis-as-gw'},
azs=['ovn'])
azs=['ovn'], enable_chassis_as_gw=True)
self.chassis4 = self.add_fake_chassis(
'ovs-host4', physical_nets=['physnet1'],
other_config={'ovn-cms-options': 'enable-chassis-as-gw'},
azs=['ovn2'])
azs=['ovn2'], enable_chassis_as_gw=True)
self._check_gateway_chassis_candidates([self.chassis3],
router_az_hints=['ovn'])

Expand All @@ -185,11 +186,9 @@ def test_gateway_chassis_with_cms_and_not_match_azs(self):
# AvailabilityZoneNotFound. after create will delete if.
# add chassis4 is having azs [ovn2], not match routers az_hints [ovn]
self.chassis3 = self.add_fake_chassis(
'ovs-host3', physical_nets=['physnet1'],
other_config={'ovn-cms-options': 'enable-chassis-as-gw'})
'ovs-host3', physical_nets=['physnet1'], enable_chassis_as_gw=True)
self.chassis4 = self.add_fake_chassis(
'ovs-host4', physical_nets=['physnet1'],
other_config={'ovn-cms-options': 'enable-chassis-as-gw'},
'ovs-host4', physical_nets=['physnet1'], enable_chassis_as_gw=True,
azs=['ovn2'])
ovn_client = self.l3_plugin._ovn_client
ext1 = self._create_ext_network(
Expand Down Expand Up @@ -217,6 +216,11 @@ def test_gateway_chassis_with_bridge_mappings_and_no_cms(self):
# Test if chassis1 is selected as candidate or not.
self._check_gateway_chassis_candidates([self.chassis1])

def test_gateway_chassis_no_physnet_tunnelled_network(self):
# The GW network is tunnelled, no physnet defined --> no possible
# candidates.
self._check_gateway_chassis_candidates([], physnet=None)

def _l3_ha_supported(self):
# If the Gateway_Chassis table exists in SB database, then it
# means that L3 HA is supported.
Expand Down
3 changes: 2 additions & 1 deletion neutron/tests/unit/agent/dhcp/test_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,7 @@ def test_dhcp_ready_ports_updates_after_enable_dhcp(self, *args):
'IpAddrCommand.wait_until_address_ready') as mock_wait:
mock_wait.return_value = True
dhcp = dhcp_agent.DhcpAgent(HOSTNAME)
dhcp.update_isolated_metadata_proxy = mock.Mock()
self.assertEqual(set(), dhcp.dhcp_ready_ports)
dhcp.configure_dhcp_for_network(fake_network)
self.assertEqual({fake_port1.id}, dhcp.dhcp_ready_ports)
Expand Down Expand Up @@ -854,7 +855,7 @@ def _enable_dhcp_helper(self, network, enable_isolated_metadata=False,
is_ovn_network):
process_instance.assert_has_calls([
mock.call.disable(sig=str(int(signal.SIGTERM))),
mock.call.enable()])
mock.call.enable(ensure_active=True)])
else:
process_instance.assert_has_calls([
mock.call.disable(sig=str(int(signal.SIGTERM)))])
Expand Down
7 changes: 6 additions & 1 deletion neutron/tests/unit/agent/metadata/test_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,12 @@ def _test_spawn_metadata_proxy(self, dad_failed=False):
'IpAddrCommand.wait_until_address_ready') as mock_wait,\
mock.patch(
'neutron.agent.linux.ip_lib.'
'delete_ip_address') as mock_del:
'delete_ip_address') as mock_del,\
mock.patch(
'neutron.agent.linux.external_process.'
'ProcessManager.active',
new_callable=mock.PropertyMock,
side_effect=[False, True]):
agent = l3_agent.L3NATAgent('localhost')
agent.process_monitor = mock.Mock()
cfg_file = os.path.join(
Expand Down
7 changes: 6 additions & 1 deletion neutron/tests/unit/agent/ovn/metadata/test_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,12 @@ def test_spawn_metadata_proxy(self):
return_value=test_utils.FakeUser(self.EUNAME)),\
mock.patch('grp.getgrnam',
return_value=test_utils.FakeGroup(self.EGNAME)),\
mock.patch('os.makedirs'):
mock.patch('os.makedirs'),\
mock.patch(
'neutron.agent.linux.external_process.'
'ProcessManager.active',
new_callable=mock.PropertyMock,
side_effect=[False, True]):
cfg_file = os.path.join(
metadata_driver.HaproxyConfigurator.get_config_path(
cfg.CONF.state_path),
Expand Down
Loading