Remove stale floating IP addresses from rfp devices

Old versions of the DVR code used to configure floating
IP addresses directly on the rfp-* devices in the
qrouter namespace.  This was changed in Mitaka to use
routes, but these stale floating IP addresses were
never cleaned-up when the l3-agent was restarted.

Add a check for these addresses and remove them at
startup if they exist.  This can be removed in a cycle
since once they are cleaned they will not be added
back by the agent.

Change-Id: Id512d213cd7ee11da913a4e4b0da20c3ad5420b0
Closes-bug: #1675187
(cherry picked from commit f84ce9a57c)
This commit is contained in:
Brian Haley 2017-03-29 16:44:57 -04:00 committed by Brian Haley
parent d599b97b40
commit a1186b9ddc
2 changed files with 28 additions and 4 deletions

View File

@ -23,6 +23,7 @@ from neutron._i18n import _, _LE, _LW
from neutron.agent.l3 import fip_rule_priority_allocator as frpa
from neutron.agent.l3 import link_local_allocator as lla
from neutron.agent.l3 import namespaces
from neutron.agent.l3 import router_info
from neutron.agent.linux import ip_lib
from neutron.agent.linux import iptables_manager
from neutron.common import constants
@ -67,6 +68,7 @@ class FipNamespace(namespaces.Namespace):
self.local_subnets = lla.LinkLocalAllocator(
path, constants.DVR_FIP_LL_CIDR)
self.destroyed = False
self._stale_fips_checked = False
@classmethod
def _get_ns_name(cls, ext_net_id):
@ -395,3 +397,17 @@ class FipNamespace(namespaces.Namespace):
device = ip_lib.IPDevice(rtr_2_fip_interface, namespace=ri.ns_name)
if device.exists():
ri.dist_fip_count = len(ri.get_router_cidrs(device))
# On upgrade, there could be stale IP addresses configured, check
# and remove them once.
# TODO(haleyb): this can go away after a cycle or two
if not self._stale_fips_checked:
stale_cidrs = (
ip for ip in router_info.RouterInfo.get_router_cidrs(
ri, device)
if common_utils.is_cidr_host(ip))
for ip_cidr in stale_cidrs:
LOG.debug("Removing stale floating ip %s from interface "
"%s in namespace %s",
ip_cidr, rtr_2_fip_interface, ri.ns_name)
device.delete_addr_and_conntrack_state(ip_cidr)
self._stale_fips_checked = True

View File

@ -20,6 +20,7 @@ from oslo_utils import uuidutils
from neutron.agent.common import utils
from neutron.agent.l3 import dvr_fip_ns
from neutron.agent.l3 import link_local_allocator as lla
from neutron.agent.l3 import router_info
from neutron.agent.linux import ip_lib
from neutron.agent.linux import iptables_manager
from neutron.common import exceptions as n_exc
@ -311,32 +312,39 @@ class TestDvrFipNs(base.BaseTestCase):
def test_create_rtr_2_fip_link_and_addr_already_exist(self):
self._test_create_rtr_2_fip_link(True, True)
@mock.patch.object(router_info.RouterInfo, 'get_router_cidrs')
@mock.patch.object(ip_lib, 'IPDevice')
def _test_scan_fip_ports(self, ri, ip_list, IPDevice):
def _test_scan_fip_ports(self, ri, ip_list, stale_list, IPDevice,
get_router_cidrs):
IPDevice.return_value = device = mock.Mock()
device.exists.return_value = True
ri.get_router_cidrs.return_value = ip_list
get_router_cidrs.return_value = stale_list
self.fip_ns.get_rtr_ext_device_name = mock.Mock(
return_value=mock.sentinel.rtr_ext_device_name)
self.fip_ns.scan_fip_ports(ri)
if stale_list:
device.delete_addr_and_conntrack_state.assert_called_once_with(
stale_list[0])
def test_scan_fip_ports_restart_fips(self):
ri = mock.Mock()
ri.dist_fip_count = None
ri.floating_ips_dict = {}
ip_list = [{'cidr': '111.2.3.4'}, {'cidr': '111.2.3.5'}]
self._test_scan_fip_ports(ri, ip_list)
stale_list = ['111.2.3.7/32']
self._test_scan_fip_ports(ri, ip_list, stale_list)
self.assertEqual(2, ri.dist_fip_count)
def test_scan_fip_ports_restart_none(self):
ri = mock.Mock()
ri.dist_fip_count = None
ri.floating_ips_dict = {}
self._test_scan_fip_ports(ri, [])
self._test_scan_fip_ports(ri, [], [])
self.assertEqual(0, ri.dist_fip_count)
def test_scan_fip_ports_restart_zero(self):
ri = mock.Mock()
ri.dist_fip_count = 0
self._test_scan_fip_ports(ri, None)
self._test_scan_fip_ports(ri, None, [])
self.assertEqual(0, ri.dist_fip_count)