Skip to content

Commit 1dc0b18

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "For hosts in DVR mode, only fetch bound FIPs" into stable/2023.1
2 parents 5833956 + fd06c73 commit 1dc0b18

File tree

4 files changed

+50
-9
lines changed

4 files changed

+50
-9
lines changed

neutron/db/l3_db.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1889,7 +1889,7 @@ def _make_floatingip_dict_with_scope(self, floatingip_obj, scope_id):
18891889
d['fixed_ip_address_scope'] = scope_id
18901890
return d
18911891

1892-
def _get_sync_floating_ips(self, context, router_ids):
1892+
def _get_sync_floating_ips(self, context, router_ids, host=None):
18931893
"""Query floating_ips that relate to list of router_ids with scope.
18941894
18951895
This is different than the regular get_floatingips in that it finds the
@@ -1905,7 +1905,7 @@ def _get_sync_floating_ips(self, context, router_ids):
19051905
return [
19061906
self._make_floatingip_dict_with_scope(*scoped_fip)
19071907
for scoped_fip in l3_obj.FloatingIP.get_scoped_floating_ips(
1908-
context, router_ids)
1908+
context, router_ids, host)
19091909
]
19101910

19111911
def _get_sync_interfaces(self, context, router_ids, device_owners=None):
@@ -2055,7 +2055,7 @@ def _process_interfaces(self, routers_dict, interfaces):
20552055
router[constants.INTERFACE_KEY] = router_interfaces
20562056

20572057
def _get_router_info_list(self, context, router_ids=None, active=None,
2058-
device_owners=None):
2058+
device_owners=None, fip_host_filter=None):
20592059
"""Query routers and their related floating_ips, interfaces."""
20602060
with db_api.CONTEXT_WRITER.using(context):
20612061
routers = self._get_sync_routers(context,
@@ -2064,7 +2064,8 @@ def _get_router_info_list(self, context, router_ids=None, active=None,
20642064
router_ids = [router['id'] for router in routers]
20652065
interfaces = self._get_sync_interfaces(
20662066
context, router_ids, device_owners)
2067-
floating_ips = self._get_sync_floating_ips(context, router_ids)
2067+
floating_ips = self._get_sync_floating_ips(
2068+
context, router_ids, host=fip_host_filter)
20682069
return (routers, interfaces, floating_ips)
20692070

20702071
def get_sync_data(self, context, router_ids=None, active=None):

neutron/db/l3_dvr_db.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -979,9 +979,17 @@ def _get_fip_agent_gw_ports(self, context, fip_agent_id):
979979
@log_helper.log_method_call
980980
def _get_dvr_sync_data(self, context, host, agent, router_ids=None,
981981
active=None):
982+
# If the requesting agent is in normal dvr mode, we can fetch
983+
# only FIPs bound to the particular host requesting the update
984+
requesting_agent_mode = self._get_agent_mode(agent)
985+
fip_host_filter = None
986+
if requesting_agent_mode == const.L3_AGENT_MODE_DVR:
987+
fip_host_filter = host
988+
982989
routers, interfaces, floating_ips = self._get_router_info_list(
983990
context, router_ids=router_ids, active=active,
984-
device_owners=const.ROUTER_INTERFACE_OWNERS)
991+
device_owners=const.ROUTER_INTERFACE_OWNERS,
992+
fip_host_filter=fip_host_filter)
985993
dvr_router_ids = set(router['id'] for router in routers
986994
if is_distributed_router(router))
987995
floating_ip_port_ids = [fip['port_id'] for fip in floating_ips
@@ -1014,7 +1022,6 @@ def _get_dvr_sync_data(self, context, host, agent, router_ids=None,
10141022
if len(l3_agent_on_host):
10151023
l3_agent_mode = self._get_agent_mode(
10161024
l3_agent_on_host[0])
1017-
requesting_agent_mode = self._get_agent_mode(agent)
10181025
# Consider the ports where the portbinding host and
10191026
# request host match.
10201027
if port_host == host:

neutron/objects/router.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from oslo_utils import versionutils
2222
from oslo_versionedobjects import fields as obj_fields
2323
from sqlalchemy import func
24+
from sqlalchemy import or_
2425
from sqlalchemy import sql
2526

2627
from neutron.db.models import dvr as dvr_models
@@ -30,6 +31,7 @@
3031
from neutron.db import models_v2
3132
from neutron.objects import base
3233
from neutron.objects.qos import binding as qos_binding
34+
from neutron.plugins.ml2 import models as ml2_models
3335

3436

3537
@base.NeutronObjectRegistry.register
@@ -390,7 +392,7 @@ def obj_make_compatible(self, primitive, target_version):
390392

391393
@classmethod
392394
@db_api.CONTEXT_READER
393-
def get_scoped_floating_ips(cls, context, router_ids):
395+
def get_scoped_floating_ips(cls, context, router_ids, host=None):
394396
query = context.session.query(l3.FloatingIP,
395397
models_v2.SubnetPool.address_scope_id)
396398
query = query.join(
@@ -405,6 +407,19 @@ def get_scoped_floating_ips(cls, context, router_ids):
405407
models_v2.SubnetPool,
406408
models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id)
407409

410+
# If a host value is provided, filter output to a specific host
411+
if host is not None:
412+
query = query.outerjoin(
413+
ml2_models.PortBinding,
414+
models_v2.Port.id == ml2_models.PortBinding.port_id)
415+
# Also filter for ports with migrating_to as they may be relevant
416+
# to this host but might not yet have the 'host' column updated
417+
# if the migration is in a pre-live migration state
418+
query = query.filter(or_(
419+
ml2_models.PortBinding.host == host,
420+
ml2_models.PortBinding.profile.like('%migrating_to%'),
421+
))
422+
408423
# Filter out on router_ids
409424
query = query.filter(l3.FloatingIP.router_id.in_(router_ids))
410425

neutron/tests/unit/objects/test_router.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717

1818
import netaddr
1919

20+
from neutron_lib.api.definitions import portbindings
2021
from neutron_lib import constants
2122
from neutron_lib.db import api as db_api
2223
from oslo_utils import uuidutils
2324

2425
from neutron.db import l3_attrs_db
26+
from neutron.objects import ports
2527
from neutron.objects.qos import binding as qos_binding
2628
from neutron.objects.qos import policy
2729
from neutron.objects import router
@@ -298,10 +300,10 @@ def test_v1_2_to_v1_1_drops_qos_network_policy_id(self):
298300
obj_v1_1['versioned_object.data'])
299301

300302
def test_get_scoped_floating_ips(self):
301-
def compare_results(router_ids, original_fips):
303+
def compare_results(router_ids, original_fips, host=None):
302304
fips_scope = [fip for fip in
303305
router.FloatingIP.get_scoped_floating_ips(
304-
self.context, router_ids)]
306+
self.context, router_ids, host=host)]
305307
fip_ids = [fip[0].id for fip in fips_scope]
306308
as_ids = {fip[1] for fip in fips_scope}
307309
self.assertCountEqual(original_fips, fip_ids)
@@ -336,11 +338,27 @@ def compare_results(router_ids, original_fips):
336338
fip.create()
337339
routers[router_id].append(fip.id)
338340

341+
# Associate port with a host
342+
port_binding = ports.PortBinding(
343+
self.context,
344+
port_id=fip.fixed_port_id,
345+
host=f"compute{j}",
346+
vif_type=portbindings.VIF_TYPE_OTHER,
347+
)
348+
port_binding.create()
349+
339350
# For each router we created, fetch the fips and ensure the
340351
# results match what we originally created
341352
for router_id, original_fips in routers.items():
342353
compare_results([router_id], original_fips)
343354

355+
# Fetch the first FIP in each router as we can assume that this is
356+
# bound to compute0, then attempt to filter by this compute host
357+
host_filtered_fips = []
358+
for router_id, original_fips in routers.items():
359+
host_filtered_fips.append(original_fips[1])
360+
compare_results(routers.keys(), host_filtered_fips, host="compute1")
361+
344362
# Now try to fetch all the fips for all the routers at once
345363
original_fips = list(chain.from_iterable(routers.values()))
346364
compare_results(routers.keys(), original_fips)

0 commit comments

Comments
 (0)