From 64028a389ff904f15e471b44bd5b3979c5db2cd2 Mon Sep 17 00:00:00 2001
From: Swaminathan Vasudevan <SVasudevan@suse.com>
Date: Fri, 23 Mar 2018 15:11:13 -0700
Subject: [PATCH] DVR: Restarting l3 agent loses centralized fip ip on
 qg-interface

When l3 agent is restarted on a dvr_snat node that is configured
for L3_HA and has a centralized FloatingIP configured to the
qg-interface in the snat_namespace, that FloatingIP is not
re-configured to the qg-interface when agent starts.

The reason being, the cidr is not being retrieved from the
keepalived instance and only retrieved from the
centralized_fip_cidr_set.

If 'L3_HA' is configured we need to retrieve it from the keepalived
instance.

This patch fixes the problem by retrieving the cidrs from the
keepalived instance for the qg-interface.

Change-Id: I848a20d06e2d344503a4cb1776dbe2617d91bc41
Closes-Bug: #1740450
---
 neutron/agent/l3/dvr_edge_ha_router.py        |  5 +++
 .../functional/agent/l3/test_dvr_router.py    | 37 +++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/neutron/agent/l3/dvr_edge_ha_router.py b/neutron/agent/l3/dvr_edge_ha_router.py
index e64f7d485af..d231c6010eb 100644
--- a/neutron/agent/l3/dvr_edge_ha_router.py
+++ b/neutron/agent/l3/dvr_edge_ha_router.py
@@ -73,6 +73,11 @@ class DvrEdgeHaRouter(dvr_edge_router.DvrEdgeRouter,
             super(DvrEdgeHaRouter, self).remove_centralized_floatingip(
                 fip_cidr)
 
+    def _get_centralized_fip_cidr_set(self):
+        interface_name = self.get_snat_external_device_interface_name(
+                self.get_ex_gw_port())
+        return set(self._get_cidrs_from_keepalived(interface_name))
+
     def external_gateway_added(self, ex_gw_port, interface_name):
         super(DvrEdgeHaRouter, self).external_gateway_added(
             ex_gw_port, interface_name)
diff --git a/neutron/tests/functional/agent/l3/test_dvr_router.py b/neutron/tests/functional/agent/l3/test_dvr_router.py
index 47123b36b5f..b64314a6f22 100644
--- a/neutron/tests/functional/agent/l3/test_dvr_router.py
+++ b/neutron/tests/functional/agent/l3/test_dvr_router.py
@@ -24,7 +24,10 @@ import six
 import testtools
 
 from neutron.agent.l3 import agent as neutron_l3_agent
+from neutron.agent.l3 import dvr_edge_ha_router as dvr_ha_router
+from neutron.agent.l3 import dvr_edge_router
 from neutron.agent.l3 import dvr_fip_ns
+from neutron.agent.l3 import dvr_local_router
 from neutron.agent.l3 import dvr_snat_ns
 from neutron.agent.l3 import namespaces
 from neutron.agent.linux import ip_lib
@@ -1277,6 +1280,40 @@ class TestDvrRouter(framework.L3AgentTestFramework):
         self._assert_no_ip_addresses_on_interface(namespace,
                                                   ex_gw_port_name)
 
+    @mock.patch.object(dvr_local_router.DvrLocalRouter, 'connect_rtr_2_fip')
+    @mock.patch.object(
+        dvr_ha_router.DvrEdgeHaRouter, '_get_centralized_fip_cidr_set')
+    def test_dvr_ha_router_with_centralized_fip_calls_keepalived_cidr(
+        self, connect_rtr_2_fip_mock, fip_cidr_centralized_mock):
+
+        self._setup_dvr_ha_agents()
+        self._setup_dvr_ha_bridges()
+
+        router1 = self._create_dvr_ha_router(
+            self.agent, enable_gw=True,
+            enable_centralized_fip=True,
+            snat_bound_fip=True)
+        self.assertTrue(fip_cidr_centralized_mock.called)
+        restarted_agent = neutron_l3_agent.L3NATAgentWithStateReport(
+            self.agent.host, self.agent.conf)
+        self.manage_router(restarted_agent, router1.router)
+        self.assertTrue(fip_cidr_centralized_mock.called)
+
+    @mock.patch.object(dvr_local_router.DvrLocalRouter, 'connect_rtr_2_fip')
+    @mock.patch.object(
+        dvr_edge_router.DvrEdgeRouter, '_get_centralized_fip_cidr_set')
+    def test_dvr_router_with_centralized_fip_calls_keepalived_cidr(
+        self, connect_rtr_2_fip_mock, fip_cidr_centralized_mock):
+
+        router_info = self.generate_dvr_router_info(
+            enable_gw=True, enable_centralized_fip=True, snat_bound_fip=True)
+        router1 = self.manage_router(self.agent, router_info)
+        self.assertTrue(fip_cidr_centralized_mock.called)
+        restarted_agent = neutron_l3_agent.L3NATAgentWithStateReport(
+            self.agent.host, self.agent.conf)
+        self.manage_router(restarted_agent, router1.router)
+        self.assertTrue(fip_cidr_centralized_mock.called)
+
     def _test_dvr_ha_router_failover_with_gw_and_fip(self, enable_gw,
                                                      enable_centralized_fip,
                                                      snat_bound_fip):