Skip to content

Commit 0615e11

Browse files
authored
Merge pull request #19 from stackhpc/upstream/yoga-2022-12-26
Synchronise yoga with upstream
2 parents 270f1da + 46c3b2b commit 0615e11

File tree

12 files changed

+459
-60
lines changed

12 files changed

+459
-60
lines changed

neutron/cmd/remove_duplicated_port_bindings.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,14 @@
2020
from oslo_db import options as db_options
2121
from oslo_log import log as logging
2222

23-
from neutron.common import config as common_config
23+
from neutron.common import config as common_config # noqa
2424
from neutron.objects import ports as ports_obj
2525

2626

2727
LOG = logging.getLogger(__name__)
2828

2929

3030
def setup_conf(conf):
31-
common_config.register_common_config_options()
3231
db_group, neutron_db_opts = db_options.list_opts()[0]
3332
conf.register_cli_opts(neutron_db_opts, db_group)
3433
conf()

neutron/common/ovn/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
OVN_GW_PORT_EXT_ID_KEY = 'neutron:gw_port_id'
3333
OVN_SUBNET_EXT_ID_KEY = 'neutron:subnet_id'
3434
OVN_SUBNET_EXT_IDS_KEY = 'neutron:subnet_ids'
35+
OVN_SUBNET_POOL_EXT_ADDR_SCOPE4_KEY = 'neutron:subnet_pool_addr_scope4'
36+
OVN_SUBNET_POOL_EXT_ADDR_SCOPE6_KEY = 'neutron:subnet_pool_addr_scope6'
3537
OVN_PHYSNET_EXT_ID_KEY = 'neutron:provnet-physical-network'
3638
OVN_NETTYPE_EXT_ID_KEY = 'neutron:provnet-network-type'
3739
OVN_SEGID_EXT_ID_KEY = 'neutron:provnet-segmentation-id'

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

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,47 @@ def check_for_igmp_snoop_support(self):
600600

601601
raise periodics.NeverAgain()
602602

603+
# TODO(czesla): Remove this in the A+4 cycle
604+
# A static spacing value is used here, but this method will only run
605+
# once per lock due to the use of periodics.NeverAgain().
606+
@periodics.periodic(spacing=600, run_immediately=True)
607+
def check_port_has_address_scope(self):
608+
if not self.has_lock:
609+
return
610+
611+
ports = self._nb_idl.db_find_rows(
612+
"Logical_Switch_Port", ("type", "!=", ovn_const.LSP_TYPE_LOCALNET)
613+
).execute(check_error=True)
614+
615+
context = n_context.get_admin_context()
616+
with self._nb_idl.transaction(check_error=True) as txn:
617+
for port in ports:
618+
if (
619+
port.external_ids.get(
620+
ovn_const.OVN_SUBNET_POOL_EXT_ADDR_SCOPE4_KEY
621+
) is None or
622+
port.external_ids.get(
623+
ovn_const.OVN_SUBNET_POOL_EXT_ADDR_SCOPE6_KEY
624+
) is None
625+
):
626+
try:
627+
port_neutron = self._ovn_client._plugin.get_port(
628+
context, port.name
629+
)
630+
631+
port_info, external_ids = (
632+
self._ovn_client.get_external_ids_from_port(
633+
port_neutron)
634+
)
635+
txn.add(self._nb_idl.set_lswitch_port(
636+
port.name, external_ids=external_ids))
637+
except n_exc.PortNotFound:
638+
# The sync function will fix this port
639+
pass
640+
except Exception:
641+
LOG.exception('Failed to update port %s', port.name)
642+
raise periodics.NeverAgain()
643+
603644
def _delete_default_ha_chassis_group(self, txn):
604645
# TODO(lucasgomes): Remove the deletion of the
605646
# HA_CHASSIS_GROUP_DEFAULT_NAME in the Y cycle. We no longer
@@ -828,7 +869,11 @@ def update_port_virtual_type(self):
828869
if lsp.type != '':
829870
continue
830871

831-
port = self._ovn_client._plugin.get_port(context, lsp.name)
872+
try:
873+
port = self._ovn_client._plugin.get_port(context, lsp.name)
874+
except n_exc.PortNotFound:
875+
continue
876+
832877
for ip in port.get('fixed_ips', []):
833878
if utils.get_virtual_port_parents(
834879
self._nb_idl, ip['ip_address'], port['network_id'],

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

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,23 @@
5858

5959

6060
OvnPortInfo = collections.namedtuple(
61-
'OvnPortInfo', ['type', 'options', 'addresses', 'port_security',
62-
'parent_name', 'tag', 'dhcpv4_options', 'dhcpv6_options',
63-
'cidrs', 'device_owner', 'security_group_ids'])
61+
"OvnPortInfo",
62+
[
63+
"type",
64+
"options",
65+
"addresses",
66+
"port_security",
67+
"parent_name",
68+
"tag",
69+
"dhcpv4_options",
70+
"dhcpv6_options",
71+
"cidrs",
72+
"device_owner",
73+
"security_group_ids",
74+
"address4_scope_id",
75+
"address6_scope_id",
76+
],
77+
)
6478

6579

6680
GW_INFO = collections.namedtuple('GatewayInfo', ['network_id', 'subnet_id',
@@ -264,6 +278,8 @@ def _get_port_options(self, port):
264278

265279
port_type = ''
266280
cidrs = ''
281+
address4_scope_id = ""
282+
address6_scope_id = ""
267283
dhcpv4_options = self._get_port_dhcp_options(port, const.IP_VERSION_4)
268284
dhcpv6_options = self._get_port_dhcp_options(port, const.IP_VERSION_6)
269285
if vtep_physical_switch:
@@ -306,6 +322,26 @@ def _get_port_options(self, port):
306322
ip_addr)
307323
continue
308324

325+
if subnet["subnetpool_id"]:
326+
try:
327+
subnet_pool = self._plugin.get_subnetpool(
328+
context, id=subnet["subnetpool_id"]
329+
)
330+
if subnet_pool["address_scope_id"]:
331+
ip_version = subnet_pool["ip_version"]
332+
if ip_version == const.IP_VERSION_4:
333+
address4_scope_id = subnet_pool[
334+
"address_scope_id"
335+
]
336+
elif ip_version == const.IP_VERSION_6:
337+
address6_scope_id = subnet_pool[
338+
"address_scope_id"
339+
]
340+
except n_exc.SubnetPoolNotFound:
341+
# swallow the exception and just continue if the
342+
# lookup failed
343+
pass
344+
309345
cidrs += ' {}/{}'.format(ip['ip_address'],
310346
subnet['cidr'].split('/')[1])
311347

@@ -403,7 +439,9 @@ def _get_port_options(self, port):
403439
sg_ids = ' '.join(utils.get_lsp_security_groups(port))
404440
return OvnPortInfo(port_type, options, addresses, port_security,
405441
parent_name, tag, dhcpv4_options, dhcpv6_options,
406-
cidrs.strip(), device_owner, sg_ids)
442+
cidrs.strip(), device_owner, sg_ids,
443+
address4_scope_id, address6_scope_id
444+
)
407445

408446
def sync_ha_chassis_group(self, context, network_id, txn):
409447
"""Return the UUID of the HA Chassis Group.
@@ -496,20 +534,32 @@ def create_port(self, context, port):
496534
if utils.is_lsp_ignored(port):
497535
return
498536

537+
def get_external_ids_from_port(self, port):
499538
port_info = self._get_port_options(port)
500539
external_ids = {ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port['name'],
501540
ovn_const.OVN_DEVID_EXT_ID_KEY: port['device_id'],
502541
ovn_const.OVN_PROJID_EXT_ID_KEY: port['project_id'],
503542
ovn_const.OVN_CIDRS_EXT_ID_KEY: port_info.cidrs,
504543
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
505544
port_info.device_owner,
545+
ovn_const.OVN_SUBNET_POOL_EXT_ADDR_SCOPE4_KEY:
546+
port_info.address4_scope_id,
547+
ovn_const.OVN_SUBNET_POOL_EXT_ADDR_SCOPE6_KEY:
548+
port_info.address6_scope_id,
506549
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY:
507550
utils.ovn_name(port['network_id']),
508551
ovn_const.OVN_SG_IDS_EXT_ID_KEY:
509552
port_info.security_group_ids,
510553
ovn_const.OVN_REV_NUM_EXT_ID_KEY: str(
511554
utils.get_revision_number(
512555
port, ovn_const.TYPE_PORTS))}
556+
return port_info, external_ids
557+
558+
def create_port(self, context, port):
559+
if utils.is_lsp_ignored(port):
560+
return
561+
562+
port_info, external_ids = self.get_external_ids_from_port(port)
513563
lswitch_name = utils.ovn_name(port['network_id'])
514564

515565
# It's possible to have a network created on one controller and then a
@@ -615,20 +665,8 @@ def _set_unset_virtual_port_type(self, context, txn, parent_port,
615665
def update_port(self, context, port, port_object=None):
616666
if utils.is_lsp_ignored(port):
617667
return
618-
port_info = self._get_port_options(port)
619-
external_ids = {ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port['name'],
620-
ovn_const.OVN_DEVID_EXT_ID_KEY: port['device_id'],
621-
ovn_const.OVN_PROJID_EXT_ID_KEY: port['project_id'],
622-
ovn_const.OVN_CIDRS_EXT_ID_KEY: port_info.cidrs,
623-
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
624-
port_info.device_owner,
625-
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY:
626-
utils.ovn_name(port['network_id']),
627-
ovn_const.OVN_SG_IDS_EXT_ID_KEY:
628-
port_info.security_group_ids,
629-
ovn_const.OVN_REV_NUM_EXT_ID_KEY: str(
630-
utils.get_revision_number(
631-
port, ovn_const.TYPE_PORTS))}
668+
669+
port_info, external_ids = self.get_external_ids_from_port(port)
632670

633671
check_rev_cmd = self._nb_idl.check_revision_number(
634672
port['id'], port, ovn_const.TYPE_PORTS)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ def match_fn(self, event, row, old=None):
336336
# don't update the AgentCache. We use chassis_private.chassis to return
337337
# data about the agent.
338338
return event == self.ROW_CREATE or (
339-
getattr(old, 'nb_cfg', False) and not
339+
hasattr(old, 'nb_cfg') and not
340340
(self.table == 'Chassis_Private' and not row.chassis))
341341

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

neutron/plugins/ml2/plugin.py

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from netaddr.strategy import eui48
2121
from neutron_lib.agent import constants as agent_consts
2222
from neutron_lib.agent import topics
23+
from neutron_lib.api import converters
2324
from neutron_lib.api.definitions import address_group as addrgrp_def
2425
from neutron_lib.api.definitions import address_scope
2526
from neutron_lib.api.definitions import agent as agent_apidef
@@ -1563,11 +1564,36 @@ def _after_create_port(self, context, result, mech_context):
15631564

15641565
return bound_context.current
15651566

1566-
def allocate_ips_for_ports(self, context, ports):
1567+
def allocate_macs_and_ips_for_ports(self, context, ports):
1568+
macs = self._generate_macs(len(ports))
1569+
network_cache = dict()
15671570
for port in ports:
15681571
port['port']['id'] = (
15691572
port['port'].get('id') or uuidutils.generate_uuid())
15701573

1574+
network_id = port['port'].get('network_id')
1575+
if network_id not in network_cache:
1576+
network = self.get_network(context, network_id)
1577+
network_cache[network_id] = network
1578+
1579+
raw_mac_address = port['port'].get('mac_address',
1580+
const.ATTR_NOT_SPECIFIED)
1581+
if raw_mac_address is const.ATTR_NOT_SPECIFIED:
1582+
raw_mac_address = macs.pop()
1583+
elif self._is_mac_in_use(context, network_id, raw_mac_address):
1584+
raise exc.MacAddressInUse(net_id=network_id,
1585+
mac=raw_mac_address)
1586+
eui_mac_address = converters.convert_to_sanitized_mac_address(
1587+
raw_mac_address)
1588+
# Create the Port object
1589+
# Note: netaddr has an issue with using the correct dialect when
1590+
# the input for EUI is another EUI object, see:
1591+
# https://github.com/netaddr/netaddr/issues/250
1592+
# TODO(lajoskatona): remove this once
1593+
# https://review.opendev.org/c/openstack/neutron-lib/+/865517 is
1594+
# released.
1595+
port['port']['mac_address'] = str(eui_mac_address)
1596+
15711597
# Call IPAM to allocate IP addresses
15721598
try:
15731599
port['ipams'] = self.ipam.allocate_ips_for_port(context, port)
@@ -1577,18 +1603,19 @@ def allocate_ips_for_ports(self, context, ports):
15771603
except ipam_exc.DeferIpam:
15781604
port['ip_allocation'] = (ipalloc_apidef.
15791605
IP_ALLOCATION_DEFERRED)
1580-
return ports
1606+
return ports, network_cache
15811607

15821608
@utils.transaction_guard
15831609
def create_port_bulk(self, context, ports):
15841610
port_list = ports.get('ports')
15851611
for port in port_list:
15861612
self._before_create_port(context, port)
15871613

1588-
port_list = self.allocate_ips_for_ports(context, port_list)
1614+
port_list, net_cache = self.allocate_macs_and_ips_for_ports(
1615+
context, port_list)
15891616

15901617
try:
1591-
return self._create_port_bulk(context, port_list)
1618+
return self._create_port_bulk(context, port_list, net_cache)
15921619
except Exception:
15931620
with excutils.save_and_reraise_exception():
15941621
# If any issue happened allocated IP addresses needs to be
@@ -1598,17 +1625,16 @@ def create_port_bulk(self, context, ports):
15981625
context, port, port['ipams'])
15991626

16001627
@db_api.retry_if_session_inactive()
1601-
def _create_port_bulk(self, context, port_list):
1628+
def _create_port_bulk(self, context, port_list, network_cache):
16021629
# TODO(njohnston): Break this up into smaller functions.
16031630
port_data = []
1604-
network_cache = dict()
1605-
macs = self._generate_macs(len(port_list))
16061631
with db_api.CONTEXT_WRITER.using(context):
16071632
for port in port_list:
16081633
# Set up the port request dict
16091634
pdata = port.get('port')
16101635
project_id = pdata.get('project_id') or pdata.get('tenant_id')
16111636
security_group_ids = pdata.get('security_groups')
1637+
network_id = pdata.get('network_id')
16121638
if security_group_ids is const.ATTR_NOT_SPECIFIED:
16131639
security_group_ids = None
16141640
else:
@@ -1620,39 +1646,21 @@ def _create_port_bulk(self, context, port_list):
16201646
bulk_port_data = dict(
16211647
project_id=project_id,
16221648
name=pdata.get('name'),
1623-
network_id=pdata.get('network_id'),
1649+
network_id=network_id,
16241650
admin_state_up=pdata.get('admin_state_up'),
16251651
status=pdata.get('status',
16261652
const.PORT_STATUS_ACTIVE),
16271653
device_id=pdata.get('device_id'),
16281654
device_owner=pdata.get('device_owner'),
16291655
description=pdata.get('description'))
16301656

1631-
# Ensure that the networks exist.
1632-
network_id = pdata.get('network_id')
1633-
if network_id not in network_cache:
1634-
network = self.get_network(context, network_id)
1635-
network_cache[network_id] = network
1636-
else:
1637-
network = network_cache[network_id]
1638-
1639-
# Determine the MAC address
1640-
raw_mac_address = pdata.get('mac_address',
1641-
const.ATTR_NOT_SPECIFIED)
1642-
if raw_mac_address is const.ATTR_NOT_SPECIFIED:
1643-
raw_mac_address = macs.pop()
1644-
elif self._is_mac_in_use(context, network_id, raw_mac_address):
1645-
raise exc.MacAddressInUse(net_id=network_id,
1646-
mac=raw_mac_address)
1647-
eui_mac_address = netaddr.EUI(raw_mac_address,
1648-
dialect=eui48.mac_unix_expanded)
1649-
port['port']['mac_address'] = str(eui_mac_address)
1650-
1651-
# Create the Port object
1652-
db_port_obj = ports_obj.Port(context,
1653-
mac_address=eui_mac_address,
1654-
id=port['port']['id'],
1655-
**bulk_port_data)
1657+
network = network_cache[network_id]
1658+
1659+
db_port_obj = ports_obj.Port(
1660+
context,
1661+
mac_address=netaddr.EUI(port['port']['mac_address'],
1662+
dialect=eui48.mac_unix_expanded),
1663+
id=port['port']['id'], **bulk_port_data)
16561664
db_port_obj.create()
16571665

16581666
# Call IPAM to store allocated IP addresses

0 commit comments

Comments
 (0)