From 9647d68fdbaabf1a340eab0116cb4889e9ae7962 Mon Sep 17 00:00:00 2001 From: venkata anil Date: Wed, 5 Jul 2017 16:35:37 +0300 Subject: [PATCH] New RPC to set HA network port status to DOWN In commit 500b255278ab41974fe6febd9a3ed13de5ddf3f6 we are using "get_router_ids" RPC to update HA network port status. But that was needed to backport that commit to other branches. As "get_router_ids" RPC is expected to fetch only router ids and not to have any other processing, we are adding new RPC "update_ha_network_port_status". L3 agent will call this new RPC to set HA network port status to DOWN. Related-bug: #1597461 Change-Id: I8f34c4f5178d2b422cfcfd082dfc9cf3f89a5d95 --- neutron/agent/l3/agent.py | 11 +++++ neutron/api/rpc/handlers/l3_rpc.py | 53 ++++++++++++---------- neutron/tests/unit/db/test_l3_hamode_db.py | 4 +- 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/neutron/agent/l3/agent.py b/neutron/agent/l3/agent.py index 3405223266f..0f9964e9a61 100644 --- a/neutron/agent/l3/agent.py +++ b/neutron/agent/l3/agent.py @@ -90,6 +90,7 @@ class L3PluginApi(object): - delete_agent_gateway_port 1.8 - Added address scope information 1.9 - Added get_router_ids + 1.10 Added update_all_ha_network_port_statuses """ def __init__(self, topic, host): @@ -103,6 +104,12 @@ class L3PluginApi(object): return cctxt.call(context, 'sync_routers', host=self.host, router_ids=router_ids) + def update_all_ha_network_port_statuses(self, context): + """Make a remote process call to update HA network port status.""" + cctxt = self.client.prepare(version='1.10') + return cctxt.call(context, 'update_all_ha_network_port_statuses', + host=self.host) + def get_router_ids(self, context): """Make a remote process call to retrieve scheduled routers ids.""" cctxt = self.client.prepare(version='1.9') @@ -569,6 +576,10 @@ class L3NATAgent(ha.AgentMixin, lib_const.L3_AGENT_MODE_DVR) try: router_ids = self.plugin_rpc.get_router_ids(context) + # We set HA network port status to DOWN to let l2 agent update it + # to ACTIVE after wiring. This allows us to spawn keepalived only + # when l2 agent finished wiring the port. + self.plugin_rpc.update_all_ha_network_port_statuses(context) # fetch routers by chunks to reduce the load on server and to # start router processing earlier for i in range(0, len(router_ids), self.sync_routers_chunk_size): diff --git a/neutron/api/rpc/handlers/l3_rpc.py b/neutron/api/rpc/handlers/l3_rpc.py index 6744f927e45..b0d32be9b15 100644 --- a/neutron/api/rpc/handlers/l3_rpc.py +++ b/neutron/api/rpc/handlers/l3_rpc.py @@ -46,7 +46,8 @@ class L3RpcCallback(object): # 1.7 Added method delete_agent_gateway_port for DVR Routers # 1.8 Added address scope information # 1.9 Added get_router_ids - target = oslo_messaging.Target(version='1.9') + # 1.10 Added update_all_ha_network_port_statuses + target = oslo_messaging.Target(version='1.10') @property def plugin(self): @@ -60,29 +61,10 @@ class L3RpcCallback(object): self._l3plugin = directory.get_plugin(plugin_constants.L3) return self._l3plugin - def _update_ha_network_port_status(self, context, host_id): - # set HA network port status to DOWN. - device_filter = { - 'device_owner': [constants.DEVICE_OWNER_ROUTER_HA_INTF], - 'status': [constants.PORT_STATUS_ACTIVE]} - ports = self.plugin.get_ports(context, filters=device_filter) - ha_ports = [p['id'] for p in ports - if p.get(portbindings.HOST_ID) == host_id] - if not ha_ports: - return - LOG.debug("L3 agent on host %(host)s requested for fullsync, so " - "setting HA network ports %(ha_ports)s status to DOWN.", - {"host": host_id, "ha_ports": ha_ports}) - for p in ha_ports: - self.plugin.update_port( - context, p, {'port': {'status': constants.PORT_STATUS_DOWN}}) + def update_all_ha_network_port_statuses(self, context, host): + """Set HA network port to DOWN for HA routers hosted on - def get_router_ids(self, context, host): - """Returns IDs of routers scheduled to l3 agent on - - This will autoschedule unhosted routers to l3 agent on and then - return all ids of routers scheduled to it. - This will also update HA network port status to down for all HA routers + This will update HA network port status to down for all HA routers hosted on . This is needed to avoid l3 agent spawning keepalived when l2 agent not yet wired the port. This can happen after a system reboot that has wiped out flows, etc and the L2 agent hasn't started up @@ -92,9 +74,30 @@ class L3RpcCallback(object): that the port is indeed ACTIVE by reacting to the port update and calling update_device_up. """ - if utils.is_extension_supported( + if not utils.is_extension_supported( self.plugin, constants.PORT_BINDING_EXT_ALIAS): - self._update_ha_network_port_status(context, host) + return + device_filter = { + 'device_owner': [constants.DEVICE_OWNER_ROUTER_HA_INTF], + 'status': [constants.PORT_STATUS_ACTIVE]} + ports = self.plugin.get_ports(context, filters=device_filter) + ha_ports = [p['id'] for p in ports + if p.get(portbindings.HOST_ID) == host] + if not ha_ports: + return + LOG.debug("L3 agent on host %(host)s requested for fullsync, so " + "setting HA network ports %(ha_ports)s status to DOWN.", + {"host": host, "ha_ports": ha_ports}) + for p in ha_ports: + self.plugin.update_port( + context, p, {'port': {'status': constants.PORT_STATUS_DOWN}}) + + def get_router_ids(self, context, host): + """Returns IDs of routers scheduled to l3 agent on + + This will autoschedule unhosted routers to l3 agent on and then + return all ids of routers scheduled to it. + """ if utils.is_extension_supported( self.l3plugin, constants.L3_AGENT_SCHEDULER_EXT_ALIAS): if cfg.CONF.router_auto_schedule: diff --git a/neutron/tests/unit/db/test_l3_hamode_db.py b/neutron/tests/unit/db/test_l3_hamode_db.py index 05c5b2187bc..38c42ae3a1f 100644 --- a/neutron/tests/unit/db/test_l3_hamode_db.py +++ b/neutron/tests/unit/db/test_l3_hamode_db.py @@ -1044,7 +1044,7 @@ class L3HAModeDbTestCase(L3HATestFramework): for port in self._get_router_port_bindings(router['id']): self.assertEqual(self.agent2['host'], port[portbindings.HOST_ID]) - def test_get_router_ids_updates_ha_network_port_status(self): + def test_update_all_ha_network_port_statuses(self): router = self._create_router(ha=True) callback = l3_rpc.L3RpcCallback() callback._l3plugin = self.plugin @@ -1071,7 +1071,7 @@ class L3HAModeDbTestCase(L3HATestFramework): ctx, port['id'], constants.PORT_STATUS_ACTIVE, host=host) port = self.core_plugin.get_port(ctx, port['id']) self.assertEqual(constants.PORT_STATUS_ACTIVE, port['status']) - callback.get_router_ids(ctx, host) + callback.update_all_ha_network_port_statuses(ctx, host) port = self.core_plugin.get_port(ctx, port['id']) self.assertEqual(constants.PORT_STATUS_DOWN, port['status'])