Browse Source

Support ports belonging to Neutron DHCP agents

Before this patch, both the sync tool and the production code
would assume that 'network:dhcp' owner ports would be for
the OVN metadata service. However, since Neutron DHCP agents
can be deployed as well on OVN environments, we need to support
these ports as well.

This change is doing several things:

- Fixing sync tool so that Neutron DHCP ports are not deleted
  anymore (these ports are owned by DHCP and have a device_id
  as 'dhcp<host_uuid>-<network_id>'). Syncing these ports in
  OVN will no longer result in creating 'localport' ports but
  normal ports to allow non-local DHCP traffic.
- Fixing networking-ovn code to skip such ports when looking
  for the metadata port on a specific network.
- Newly created metadata ports will have a device_id such as
  'ovnmeta-<network_id>'.

Change-Id: I30181e1752f456f30f94818c5350f447c387cbb2
Related-Bug: #1804390
Signed-off-by: Daniel Alvarez <dalvarez@redhat.com>
Daniel Alvarez 5 months ago
parent
commit
d28495fe42

+ 0
- 2
networking_ovn/common/constants.py View File

@@ -52,8 +52,6 @@ OVN_DROP_PORT_GROUP_NAME = 'neutron_pg_drop'
52 52
 
53 53
 OVN_PROVNET_PORT_NAME_PREFIX = 'provnet-'
54 54
 
55
-OVN_NEUTRON_OWNER_TO_PORT_TYPE = {const.DEVICE_OWNER_DHCP: 'localport'}
56
-
57 55
 # Agent extension constants
58 56
 OVN_AGENT_DESC_KEY = 'neutron:description'
59 57
 OVN_AGENT_METADATA_SB_CFG_KEY = 'neutron:ovn-metadata-sb-cfg'

+ 15
- 6
networking_ovn/common/ovn_client.py View File

@@ -196,6 +196,7 @@ class OVNClient(object):
196 196
             qos_options = self._qos_driver.get_qos_options(port)
197 197
         vtep_physical_switch = binding_prof.get('vtep-physical-switch')
198 198
 
199
+        port_type = ''
199 200
         cidrs = ''
200 201
         if vtep_physical_switch:
201 202
             vtep_logical_switch = binding_prof.get('vtep-logical-switch')
@@ -224,8 +225,12 @@ class OVNClient(object):
224 225
                 self._get_allowed_addresses_from_port(port)
225 226
             addresses = [address]
226 227
             addresses.extend(new_macs)
227
-            port_type = ovn_const.OVN_NEUTRON_OWNER_TO_PORT_TYPE.get(
228
-                port['device_owner'], '')
228
+
229
+            # Only adjust the OVN type if the port is not owned by Neutron
230
+            # DHCP agents.
231
+            if (port['device_owner'] == const.DEVICE_OWNER_DHCP and
232
+                    not port['device_id'].startswith('dhcp')):
233
+                port_type = 'localport'
229 234
 
230 235
         dhcpv4_options = self._get_port_dhcp_options(port, const.IP_VERSION_4)
231 236
         dhcpv6_options = self._get_port_dhcp_options(port, const.IP_VERSION_6)
@@ -1740,9 +1745,12 @@ class OVNClient(object):
1740 1745
 
1741 1746
         ports = self._plugin.get_ports(context, filters=dict(
1742 1747
             network_id=[network_id], device_owner=[const.DEVICE_OWNER_DHCP]))
1743
-        # There should be only one metadata port per network
1744
-        if len(ports) == 1:
1745
-            return ports[0]
1748
+
1749
+        # Metadata ports are DHCP ports without a device_id starting by 'dhcp'
1750
+        # since those belong to Neutron DHCP agents.
1751
+        for port in ports:
1752
+            if not port['device_id'].startswith('dhcp'):
1753
+                return port
1746 1754
 
1747 1755
     def _find_metadata_port_ip(self, context, subnet):
1748 1756
         metadata_port = self._find_metadata_port(context, subnet['network_id'])
@@ -1766,7 +1774,8 @@ class OVNClient(object):
1766 1774
                 port = {'port':
1767 1775
                         {'network_id': network['id'],
1768 1776
                          'tenant_id': network['project_id'],
1769
-                         'device_owner': const.DEVICE_OWNER_DHCP}}
1777
+                         'device_owner': const.DEVICE_OWNER_DHCP,
1778
+                         'device_id': 'ovnmeta-%s' % network['id']}}
1770 1779
                 # TODO(boden): rehome create_port into neutron-lib
1771 1780
                 p_utils.create_port(self._plugin, context, port)
1772 1781
             elif len(metadata_ports) > 1:

+ 8
- 0
networking_ovn/ovn_db_sync.py View File

@@ -896,6 +896,14 @@ class OvnNbSynchronizer(OvnDbSynchronizer):
896 896
             dhcp_ports = self.core_plugin.get_ports(ctx, filters=dict(
897 897
                 network_id=[net['id']],
898 898
                 device_owner=[constants.DEVICE_OWNER_DHCP]))
899
+
900
+            for port in dhcp_ports:
901
+                # Ports with a device_id like 'dhcp<host_id>-<network_id>'
902
+                # belong to Neutron DHCP agent so we'll skip those for OVN
903
+                # metadata.
904
+                if port['device_id'].startswith('dhcp'):
905
+                    dhcp_ports.remove(port)
906
+
899 907
             if not dhcp_ports:
900 908
                 LOG.warning('Missing metadata port found in Neutron for '
901 909
                             'network %s', net['id'])

+ 6
- 6
networking_ovn/tests/functional/test_ovn_db_sync.py View File

@@ -885,7 +885,8 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
885 885
         db_metadata_ports_ids = []
886 886
         db_metadata_ports_nets = []
887 887
         for port in db_ports['ports']:
888
-            if port['device_owner'] == constants.DEVICE_OWNER_DHCP:
888
+            if (port['device_owner'] == constants.DEVICE_OWNER_DHCP and
889
+                    port['device_id'].startswith('ovnmeta')):
889 890
                 db_metadata_ports_ids.append(port['id'])
890 891
                 db_metadata_ports_nets.append(port['network_id'])
891 892
         db_networks = self._list('networks')
@@ -895,8 +896,7 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
895 896
         _plugin_nb_ovn = self.mech_driver._nb_ovn
896 897
         plugin_metadata_ports = [row.name for row in (
897 898
             _plugin_nb_ovn._tables['Logical_Switch_Port'].rows.values())
898
-            if row.type == ovn_const.OVN_NEUTRON_OWNER_TO_PORT_TYPE.get(
899
-                constants.DEVICE_OWNER_DHCP)]
899
+            if row.type == 'localport']
900 900
 
901 901
         if should_match:
902 902
             # Check that metadata ports exist in both Neutron and OVN dbs.
@@ -1402,7 +1402,8 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
1402 1402
         db_ports = self._list('ports')
1403 1403
         db_metadata_ports = [port for port in db_ports['ports'] if
1404 1404
                              port['device_owner'] ==
1405
-                             constants.DEVICE_OWNER_DHCP]
1405
+                             constants.DEVICE_OWNER_DHCP and
1406
+                             port['device_id'].startswith('ovnmeta')]
1406 1407
         lswitches = {}
1407 1408
         ports_to_delete = len(db_metadata_ports) / 2
1408 1409
         for port in db_metadata_ports:
@@ -1414,8 +1415,7 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
1414 1415
         _plugin_nb_ovn = self.mech_driver._nb_ovn
1415 1416
         plugin_metadata_ports = [row.name for row in (
1416 1417
             _plugin_nb_ovn._tables['Logical_Switch_Port'].rows.values())
1417
-            if row.type == ovn_const.OVN_NEUTRON_OWNER_TO_PORT_TYPE.get(
1418
-                constants.DEVICE_OWNER_DHCP)]
1418
+            if row.type == 'localport']
1419 1419
 
1420 1420
         with self.nb_api.transaction(check_error=True) as txn:
1421 1421
             for port in plugin_metadata_ports:

Loading…
Cancel
Save