DVR: Configure centralized floatingips to snat_namespace.
This patch is the agent side patch that takes care of configuring the centralized floatingips for the unbound ports in the snat_namespace. Change-Id: I595ce4d6520adfd57bacbdf20ed03ffefd0b190a Closes-Bug: #1583694
This commit is contained in:
parent
5d5ebd0bd9
commit
8b4bb9c0b0
@ -21,6 +21,7 @@ from neutron.agent.l3 import dvr_snat_ns
|
||||
from neutron.agent.l3 import router_info as router
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.agent.linux import iptables_manager
|
||||
from neutron.common import constants as n_const
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -260,3 +261,92 @@ class DvrEdgeRouter(dvr_local_router.DvrLocalRouter):
|
||||
bridge=self.agent_conf.external_network_bridge,
|
||||
namespace=self.snat_namespace.name,
|
||||
prefix=router.EXTERNAL_DEV_PREFIX)
|
||||
|
||||
def get_snat_external_device_interface_name(self, ex_gw_port):
|
||||
long_name = router.EXTERNAL_DEV_PREFIX + ex_gw_port['id']
|
||||
return long_name[:self.driver.DEV_NAME_LEN]
|
||||
|
||||
def _get_centralized_fip_cidr_set(self):
|
||||
"""Returns the fip_cidr set for centralized floatingips."""
|
||||
interface_name = self.get_snat_external_device_interface_name(
|
||||
self.get_ex_gw_port())
|
||||
device = ip_lib.IPDevice(
|
||||
interface_name, namespace=self.snat_namespace.name)
|
||||
return set([addr['cidr'] for addr in device.addr.list()])
|
||||
|
||||
def get_router_cidrs(self, device):
|
||||
"""Over-ride the get_router_cidrs function to return the list.
|
||||
|
||||
This function is overridden to provide the complete list of
|
||||
floating_ip cidrs that the router hosts.
|
||||
This includes the centralized floatingip cidr list and the
|
||||
regular floatingip cidr list that are bound to fip namespace.
|
||||
"""
|
||||
fip_cidrs = super(DvrEdgeRouter, self).get_router_cidrs(device)
|
||||
centralized_cidrs = set()
|
||||
if self.get_ex_gw_port():
|
||||
centralized_cidrs = self._get_centralized_fip_cidr_set()
|
||||
return fip_cidrs | centralized_cidrs
|
||||
|
||||
def remove_centralized_floatingip(self, fip_cidr):
|
||||
"""Function to handle the centralized Floatingip remove."""
|
||||
if not self.get_ex_gw_port():
|
||||
return
|
||||
if not self._is_this_snat_host():
|
||||
return
|
||||
interface_name = self.get_snat_external_device_interface_name(
|
||||
self.get_ex_gw_port())
|
||||
device = ip_lib.IPDevice(
|
||||
interface_name, namespace=self.snat_namespace.name)
|
||||
device.delete_addr_and_conntrack_state(fip_cidr)
|
||||
self.process_floating_ip_nat_rules_for_centralized_floatingip()
|
||||
|
||||
def add_centralized_floatingip(self, fip, fip_cidr):
|
||||
"""Function to handle the centralized Floatingip addition."""
|
||||
if not self.get_ex_gw_port():
|
||||
return
|
||||
if not self._is_this_snat_host():
|
||||
return
|
||||
interface_name = self.get_snat_external_device_interface_name(
|
||||
self.get_ex_gw_port())
|
||||
device = ip_lib.IPDevice(
|
||||
interface_name, namespace=self.snat_namespace.name)
|
||||
try:
|
||||
device.addr.add(fip_cidr)
|
||||
except RuntimeError:
|
||||
LOG.warning("Unable to configure IP address for centralized "
|
||||
"floating IP: %s", fip['id'])
|
||||
return lib_constants.FLOATINGIP_STATUS_ERROR
|
||||
self.process_floating_ip_nat_rules_for_centralized_floatingip()
|
||||
# Send a GARP message on the external interface for the
|
||||
# centralized floatingip configured.
|
||||
ip_lib.send_ip_addr_adv_notif(self.snat_namespace.name,
|
||||
interface_name,
|
||||
fip['floating_ip_address'],
|
||||
self.agent_conf)
|
||||
return lib_constants.FLOATINGIP_STATUS_ACTIVE
|
||||
|
||||
def _centralized_floating_forward_rules(self, floating_ip, fixed_ip):
|
||||
return [('PREROUTING', '-d %s/32 -j DNAT --to-destination %s' %
|
||||
(floating_ip, fixed_ip)),
|
||||
('OUTPUT', '-d %s/32 -j DNAT --to-destination %s' %
|
||||
(floating_ip, fixed_ip)),
|
||||
('float-snat', '-s %s/32 -j SNAT --to-source %s' %
|
||||
(fixed_ip, floating_ip))]
|
||||
|
||||
def _set_floating_ip_nat_rules_for_centralized_floatingip(self, fip):
|
||||
if fip.get(n_const.DVR_SNAT_BOUND):
|
||||
fixed = fip['fixed_ip_address']
|
||||
fip_ip = fip['floating_ip_address']
|
||||
for chain, rule in self._centralized_floating_forward_rules(
|
||||
fip_ip, fixed):
|
||||
self.snat_iptables_manager.ipv4['nat'].add_rule(
|
||||
chain, rule, tag='floating_ip')
|
||||
|
||||
def process_floating_ip_nat_rules_for_centralized_floatingip(self):
|
||||
self.snat_iptables_manager.ipv4['nat'].clear_rules_by_tag(
|
||||
'floating_ip')
|
||||
floating_ips = self.get_floating_ips()
|
||||
for fip in floating_ips:
|
||||
self._set_floating_ip_nat_rules_for_centralized_floatingip(fip)
|
||||
self.snat_iptables_manager.apply()
|
||||
|
@ -43,24 +43,23 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
|
||||
super(DvrLocalRouter, self).__init__(host, *args, **kwargs)
|
||||
|
||||
self.floating_ips_dict = {}
|
||||
self.centralized_floatingips_set = set()
|
||||
# Linklocal subnet for router and floating IP namespace link
|
||||
self.rtr_fip_subnet = None
|
||||
self.rtr_fip_connect = False
|
||||
self.fip_ns = None
|
||||
self._pending_arp_set = set()
|
||||
|
||||
def get_floating_ips(self):
|
||||
"""Filter Floating IPs to be hosted on this agent."""
|
||||
floating_ips = super(DvrLocalRouter, self).get_floating_ips()
|
||||
return [i for i in floating_ips if (
|
||||
(i['host'] == self.host) or
|
||||
(i.get('dest_host') == self.host))]
|
||||
|
||||
def floating_forward_rules(self, floating_ip, fixed_ip):
|
||||
def floating_forward_rules(self, fip):
|
||||
"""Override this function defined in router_info for dvr routers."""
|
||||
if not self.fip_ns:
|
||||
return []
|
||||
|
||||
if fip.get(n_const.DVR_SNAT_BOUND):
|
||||
return []
|
||||
|
||||
fixed_ip = fip['fixed_ip_address']
|
||||
floating_ip = fip['floating_ip_address']
|
||||
rtr_2_fip_name = self.fip_ns.get_rtr_ext_device_name(self.router_id)
|
||||
dnat_from_floatingip_to_fixedip = (
|
||||
'PREROUTING', '-d %s/32 -i %s -j DNAT --to-destination %s' % (
|
||||
@ -83,8 +82,25 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
|
||||
'FORWARD', '-s %s/32 -j $float-snat' % fixed_ip)
|
||||
return [mark_traffic_to_floating_ip, mark_traffic_from_fixed_ip]
|
||||
|
||||
def add_centralized_floatingip(self, fip, fip_cidr):
|
||||
"""Implements floatingip in centralized network node.
|
||||
This is a dummy function and is overridden in dvr_edge_router.py
|
||||
to add the floatingip function to the snat namespace.
|
||||
"""
|
||||
|
||||
def remove_centralized_floatingip(self, fip_cidr):
|
||||
"""Removes floatingip from centralized network node.
|
||||
This is a dummy function and is overridden in dvr_edge_router.py
|
||||
to remove the floatingip function from the snat namespace.
|
||||
"""
|
||||
|
||||
def floating_ip_added_dist(self, fip, fip_cidr):
|
||||
"""Add floating IP to FIP namespace."""
|
||||
if fip.get(n_const.DVR_SNAT_BOUND):
|
||||
floating_ip_status = self.add_centralized_floatingip(fip, fip_cidr)
|
||||
if floating_ip_status == lib_constants.FLOATINGIP_STATUS_ACTIVE:
|
||||
self.centralized_floatingips_set.add(fip_cidr)
|
||||
return floating_ip_status
|
||||
floating_ip = fip['floating_ip_address']
|
||||
fixed_ip = fip['fixed_ip_address']
|
||||
self._add_floating_ip_rule(floating_ip, fixed_ip)
|
||||
@ -103,6 +119,7 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
|
||||
ip_lib.send_ip_addr_adv_notif(fip_ns_name,
|
||||
interface_name,
|
||||
floating_ip)
|
||||
return lib_constants.FLOATINGIP_STATUS_ACTIVE
|
||||
|
||||
def _add_floating_ip_rule(self, floating_ip, fixed_ip):
|
||||
rule_pr = self.fip_ns.allocate_rule_priority(floating_ip)
|
||||
@ -124,6 +141,10 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
|
||||
|
||||
def floating_ip_removed_dist(self, fip_cidr):
|
||||
"""Remove floating IP from FIP namespace."""
|
||||
if fip_cidr in self.centralized_floatingips_set:
|
||||
self.remove_centralized_floatingip(fip_cidr)
|
||||
self.centralized_floatingips_set.remove(fip_cidr)
|
||||
return
|
||||
floating_ip = fip_cidr.split('/')[0]
|
||||
fip_2_rtr_name = self.fip_ns.get_int_device_name(self.router_id)
|
||||
if self.rtr_fip_subnet is None:
|
||||
@ -147,8 +168,7 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
|
||||
def add_floating_ip(self, fip, interface_name, device):
|
||||
# Special Handling for DVR - update FIP namespace
|
||||
ip_cidr = common_utils.ip_to_cidr(fip['floating_ip_address'])
|
||||
self.floating_ip_added_dist(fip, ip_cidr)
|
||||
return lib_constants.FLOATINGIP_STATUS_ACTIVE
|
||||
return self.floating_ip_added_dist(fip, ip_cidr)
|
||||
|
||||
def remove_floating_ip(self, device, ip_cidr):
|
||||
self.floating_ip_removed_dist(ip_cidr)
|
||||
@ -417,7 +437,13 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
|
||||
return next(
|
||||
(p for p in fip_ports if p['network_id'] == ext_net_id), None)
|
||||
|
||||
def get_snat_external_device_interface_name(self, port_id):
|
||||
pass
|
||||
|
||||
def get_external_device_interface_name(self, ex_gw_port):
|
||||
floating_ips = self.get_floating_ips()
|
||||
if not self._get_floatingips_bound_to_host(floating_ips):
|
||||
return self.get_snat_external_device_interface_name(ex_gw_port)
|
||||
fip_int = self.fip_ns.get_int_device_name(self.router_id)
|
||||
if ip_lib.device_exists(fip_int, namespace=self.fip_ns.get_name()):
|
||||
return self.fip_ns.get_rtr_ext_device_name(self.router_id)
|
||||
@ -519,6 +545,12 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase):
|
||||
ext_scope_mark)
|
||||
return ports_scopemark
|
||||
|
||||
def _get_floatingips_bound_to_host(self, floating_ips):
|
||||
"""Filter Floating IPs to be hosted on this agent."""
|
||||
return [i for i in floating_ips
|
||||
if (i['host'] == self.host or
|
||||
i.get('dest_host') == self.host)]
|
||||
|
||||
def process_external(self):
|
||||
ex_gw_port = self.get_ex_gw_port()
|
||||
if ex_gw_port:
|
||||
|
@ -161,7 +161,9 @@ class RouterInfo(object):
|
||||
"""Filter Floating IPs to be hosted on this agent."""
|
||||
return self.router.get(lib_constants.FLOATINGIP_KEY, [])
|
||||
|
||||
def floating_forward_rules(self, floating_ip, fixed_ip):
|
||||
def floating_forward_rules(self, fip):
|
||||
fixed_ip = fip['fixed_ip_address']
|
||||
floating_ip = fip['floating_ip_address']
|
||||
return [('PREROUTING', '-d %s/32 -j DNAT --to-destination %s' %
|
||||
(floating_ip, fixed_ip)),
|
||||
('OUTPUT', '-d %s/32 -j DNAT --to-destination %s' %
|
||||
@ -215,9 +217,7 @@ class RouterInfo(object):
|
||||
# Loop once to ensure that floating ips are configured.
|
||||
for fip in floating_ips:
|
||||
# Rebuild iptables rules for the floating ip.
|
||||
fixed = fip['fixed_ip_address']
|
||||
fip_ip = fip['floating_ip_address']
|
||||
for chain, rule in self.floating_forward_rules(fip_ip, fixed):
|
||||
for chain, rule in self.floating_forward_rules(fip):
|
||||
self.iptables_manager.ipv4['nat'].add_rule(chain, rule,
|
||||
tag='floating_ip')
|
||||
|
||||
|
@ -445,6 +445,7 @@ class TestDvrRouter(framework.L3AgentTestFramework):
|
||||
enable_ha=False,
|
||||
enable_snat=False,
|
||||
enable_gw=True,
|
||||
snat_bound_fip=False,
|
||||
agent=None,
|
||||
extra_routes=False,
|
||||
enable_floating_ip=True,
|
||||
@ -465,6 +466,9 @@ class TestDvrRouter(framework.L3AgentTestFramework):
|
||||
if enable_floating_ip:
|
||||
floating_ip = router['_floatingips'][0]
|
||||
floating_ip['host'] = agent.conf.host
|
||||
|
||||
if snat_bound_fip:
|
||||
floating_ip[n_const.DVR_SNAT_BOUND] = True
|
||||
if enable_gw:
|
||||
external_gw_port = router['gw_port']
|
||||
router['gw_port'][portbindings.HOST_ID] = agent.conf.host
|
||||
@ -481,6 +485,7 @@ class TestDvrRouter(framework.L3AgentTestFramework):
|
||||
floating_ip['port_id'] = internal_ports[0]['id']
|
||||
floating_ip['status'] = 'ACTIVE'
|
||||
|
||||
if not snat_bound_fip:
|
||||
self._add_fip_agent_gw_port_info_to_router(router,
|
||||
external_gw_port)
|
||||
return router
|
||||
@ -683,10 +688,7 @@ class TestDvrRouter(framework.L3AgentTestFramework):
|
||||
|
||||
# In the router namespace, check the iptables rules are set correctly
|
||||
for fip in floating_ips:
|
||||
floatingip = fip['floating_ip_address']
|
||||
fixedip = fip['fixed_ip_address']
|
||||
expected_rules = router.floating_forward_rules(floatingip,
|
||||
fixedip)
|
||||
expected_rules = router.floating_forward_rules(fip)
|
||||
self._assert_iptables_rules_exist(
|
||||
router.iptables_manager, 'nat', expected_rules)
|
||||
|
||||
@ -986,6 +988,19 @@ class TestDvrRouter(framework.L3AgentTestFramework):
|
||||
internal_dev_name, namespace=snat_ns)
|
||||
return qg_device_created_successfully, sg_device_created_successfully
|
||||
|
||||
def test_snat_bound_floating_ip(self):
|
||||
"""Test to validate the snat bound floatingip lifecycle."""
|
||||
self.agent.conf.agent_mode = lib_constants.L3_AGENT_MODE_DVR_SNAT
|
||||
router_info = self.generate_dvr_router_info(snat_bound_fip=True)
|
||||
router1 = self.manage_router(self.agent, router_info)
|
||||
snat_bound_floatingips = router_info[lib_constants.FLOATINGIP_KEY]
|
||||
self._assert_snat_namespace_exists(router1)
|
||||
# In the snat namespace, check the iptables rules are set correctly
|
||||
for fip in snat_bound_floatingips:
|
||||
expected_rules = router1.floating_forward_rules(fip)
|
||||
self._assert_iptables_rules_exist(
|
||||
router1.snat_iptables_manager, 'nat', expected_rules)
|
||||
|
||||
def test_dvr_router_snat_namespace_with_interface_remove(self):
|
||||
"""Test to validate the snat namespace with interface remove.
|
||||
|
||||
|
@ -1182,6 +1182,8 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
||||
fip_gw_port.return_value = agent_gateway_port[0]
|
||||
ri.create_dvr_external_gateway_on_agent(ext_gw_port)
|
||||
ri.connect_rtr_2_fip()
|
||||
ri._get_floatingips_bound_to_host = mock.Mock(
|
||||
return_value=True)
|
||||
self.assertTrue(fip_gw_port.called)
|
||||
self.assertTrue(create_fip.called)
|
||||
self.assertEqual(agent_gateway_port[0],
|
||||
@ -1200,6 +1202,72 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
||||
create_fip.assert_called_once_with()
|
||||
self.assertEqual(1, ri.fip_ns.create_rtr_2_fip_link.call_count)
|
||||
|
||||
@mock.patch.object(lla.LinkLocalAllocator, '_write')
|
||||
def test_floating_ip_centralized(self, lla_write):
|
||||
fake_network_id = _uuid()
|
||||
subnet_id = _uuid()
|
||||
fake_floatingips = {'floatingips': [
|
||||
{'id': _uuid(),
|
||||
'floating_ip_address': '20.0.0.3',
|
||||
'fixed_ip_address': '192.168.0.1',
|
||||
'floating_network_id': _uuid(),
|
||||
'port_id': _uuid(),
|
||||
'dvr_snat_bound': True,
|
||||
'host': None}]}
|
||||
agent_gateway_port = (
|
||||
[{'fixed_ips': [
|
||||
{'ip_address': '20.0.0.30',
|
||||
'prefixlen': 24,
|
||||
'subnet_id': subnet_id}],
|
||||
'subnets': [
|
||||
{'id': subnet_id,
|
||||
'cidr': '20.0.0.0/24',
|
||||
'gateway_ip': '20.0.0.1'}],
|
||||
'id': _uuid(),
|
||||
'network_id': fake_network_id,
|
||||
'mac_address': 'ca:fe:de:ad:be:ef'}]
|
||||
)
|
||||
|
||||
router = l3_test_common.prepare_router_data(enable_snat=True)
|
||||
router[lib_constants.FLOATINGIP_KEY] = fake_floatingips['floatingips']
|
||||
router[n_const.FLOATINGIP_AGENT_INTF_KEY] = agent_gateway_port
|
||||
router['distributed'] = True
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
self._set_ri_kwargs(agent, router['id'], router)
|
||||
ri = dvr_router.DvrEdgeRouter(HOSTNAME, **self.ri_kwargs)
|
||||
ext_gw_port = ri.router.get('gw_port')
|
||||
ri.fip_ns = agent.get_fip_ns(ext_gw_port['network_id'])
|
||||
agent.process_router_add = mock.Mock()
|
||||
ri.fip_ns.create_rtr_2_fip_link = mock.Mock()
|
||||
with mock.patch.object(ri, 'get_floating_ips') as fips, \
|
||||
mock.patch.object(ri,
|
||||
'add_centralized_floatingip') as add_fip, \
|
||||
mock.patch.object(ri, 'get_floating_agent_gw_interface'
|
||||
) as fip_gw_port, \
|
||||
mock.patch.object(ri.fip_ns,
|
||||
'create') as create_fip, \
|
||||
mock.patch.object(ri,
|
||||
'remove_centralized_floatingip') as rem_fip:
|
||||
fips.return_value = fake_floatingips
|
||||
fip_gw_port.return_value = agent_gateway_port[0]
|
||||
add_fip.return_value = lib_constants.FLOATINGIP_STATUS_ACTIVE
|
||||
ri.create_dvr_external_gateway_on_agent(ext_gw_port)
|
||||
ri.connect_rtr_2_fip()
|
||||
self.assertTrue(fip_gw_port.called)
|
||||
self.assertTrue(create_fip.called)
|
||||
self.assertEqual(agent_gateway_port[0],
|
||||
ri.fip_ns.agent_gateway_port)
|
||||
self.assertTrue(ri.rtr_fip_connect)
|
||||
# Now let us associate the fip to the router
|
||||
status = ri.floating_ip_added_dist(fips, "192.168.0.1/32")
|
||||
add_fip.assert_called_once_with(fips, "192.168.0.1/32")
|
||||
self.assertEqual(lib_constants.FLOATINGIP_STATUS_ACTIVE, status)
|
||||
self.assertEqual(set(["192.168.0.1/32"]),
|
||||
ri.centralized_floatingips_set)
|
||||
ri.floating_ip_removed_dist("192.168.0.1/32")
|
||||
rem_fip.assert_called_once_with("192.168.0.1/32")
|
||||
self.assertEqual(set([]), ri.centralized_floatingips_set)
|
||||
|
||||
@mock.patch.object(lla.LinkLocalAllocator, '_write')
|
||||
def test_create_dvr_fip_interfaces_for_late_binding(self, lla_write):
|
||||
fake_network_id = _uuid()
|
||||
@ -1291,6 +1359,8 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
||||
fip_gw_port.return_value = agent_gateway_port[0]
|
||||
ri.create_dvr_external_gateway_on_agent(ext_gw_port)
|
||||
ri.connect_rtr_2_fip()
|
||||
ri._get_floatingips_bound_to_host = mock.Mock(
|
||||
return_value=True)
|
||||
self.assertTrue(fip_gw_port.called)
|
||||
self.assertEqual(agent_gateway_port[0],
|
||||
ri.fip_ns.agent_gateway_port)
|
||||
@ -1339,6 +1409,8 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
||||
fip_gw_port.return_value = agent_gateway_port[0]
|
||||
ri.create_dvr_external_gateway_on_agent(ext_gw_port)
|
||||
ri.connect_rtr_2_fip()
|
||||
ri._get_floatingips_bound_to_host = mock.Mock(
|
||||
return_value=True)
|
||||
self.assertTrue(fip_gw_port.called)
|
||||
self.assertEqual(agent_gateway_port[0],
|
||||
ri.fip_ns.agent_gateway_port)
|
||||
|
@ -21,6 +21,7 @@ from oslo_log import log
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from neutron.agent.l3 import agent as l3_agent
|
||||
from neutron.agent.l3 import dvr_edge_router as dvr_edge_rtr
|
||||
from neutron.agent.l3 import dvr_local_router as dvr_router
|
||||
from neutron.agent.l3 import link_local_allocator as lla
|
||||
from neutron.agent.l3 import router_info
|
||||
@ -178,6 +179,7 @@ class TestDvrRouterOperations(base.BaseTestCase):
|
||||
ri.rtr_fip_connect = True
|
||||
ex_gw_port = {'network_id': 'fake_net_id'}
|
||||
ri.create_dvr_external_gateway_on_agent(ex_gw_port)
|
||||
ri._get_floatingips_bound_to_host = mock.Mock(return_value=True)
|
||||
ri.fip_ns.create_or_update_gateway_port.assert_called_once_with(
|
||||
fip_agent_port)
|
||||
|
||||
@ -231,16 +233,16 @@ class TestDvrRouterOperations(base.BaseTestCase):
|
||||
|
||||
fips = ri.get_floating_ips()
|
||||
|
||||
self.assertEqual([{'host': HOSTNAME}], fips)
|
||||
self.assertEqual(
|
||||
[{'host': HOSTNAME}, {'host': mock.sentinel.otherhost}], fips)
|
||||
|
||||
def test_floating_forward_rules_no_fip_ns(self):
|
||||
router = mock.MagicMock()
|
||||
router.get.return_value = [{'host': HOSTNAME},
|
||||
{'host': mock.sentinel.otherhost}]
|
||||
fip = {'id': _uuid()}
|
||||
ri = self._create_router(router)
|
||||
floating_ip = mock.Mock()
|
||||
fixed_ip = mock.Mock()
|
||||
self.assertFalse(ri.floating_forward_rules(floating_ip, fixed_ip))
|
||||
self.assertFalse(ri.floating_forward_rules(fip))
|
||||
|
||||
def test_floating_forward_rules(self):
|
||||
router = mock.MagicMock()
|
||||
@ -250,6 +252,9 @@ class TestDvrRouterOperations(base.BaseTestCase):
|
||||
floating_ip = '15.1.2.3'
|
||||
rtr_2_fip_name = 'fake_router'
|
||||
fixed_ip = '192.168.0.1'
|
||||
fip = {'id': _uuid(),
|
||||
'fixed_ip_address': '192.168.0.1',
|
||||
'floating_ip_address': '15.1.2.3'}
|
||||
instance = mock.Mock()
|
||||
instance.get_rtr_ext_device_name = mock.Mock(
|
||||
return_value=rtr_2_fip_name)
|
||||
@ -260,7 +265,7 @@ class TestDvrRouterOperations(base.BaseTestCase):
|
||||
snat_from_fixedip_to_floatingip = (
|
||||
'float-snat', '-s %s/32 -j SNAT --to-source %s' % (
|
||||
fixed_ip, floating_ip))
|
||||
actual = ri.floating_forward_rules(floating_ip, fixed_ip)
|
||||
actual = ri.floating_forward_rules(fip)
|
||||
expected = [dnat_from_floatingip_to_fixedip,
|
||||
snat_from_fixedip_to_floatingip]
|
||||
self.assertEqual(expected, actual)
|
||||
@ -405,9 +410,13 @@ class TestDvrRouterOperations(base.BaseTestCase):
|
||||
table=16,
|
||||
priority=FIP_PRI)
|
||||
|
||||
def _test_add_floating_ip(self, ri, fip, is_failure):
|
||||
ri.floating_ip_added_dist = mock.Mock()
|
||||
|
||||
def _test_add_floating_ip(self, ri, fip, is_failure=False):
|
||||
if not is_failure:
|
||||
ri.floating_ip_added_dist = mock.Mock(
|
||||
return_value=lib_constants.FLOATINGIP_STATUS_ACTIVE)
|
||||
else:
|
||||
ri.floating_ip_added_dist = mock.Mock(
|
||||
return_value=lib_constants.FLOATINGIP_STATUS_ERROR)
|
||||
result = ri.add_floating_ip(fip,
|
||||
mock.sentinel.interface_name,
|
||||
mock.sentinel.device)
|
||||
@ -419,10 +428,18 @@ class TestDvrRouterOperations(base.BaseTestCase):
|
||||
ri = self._create_router(mock.MagicMock())
|
||||
ip = '15.1.2.3'
|
||||
fip = {'floating_ip_address': ip}
|
||||
result = self._test_add_floating_ip(ri, fip, True)
|
||||
result = self._test_add_floating_ip(ri, fip)
|
||||
ri.floating_ip_added_dist.assert_called_once_with(fip, ip + '/32')
|
||||
self.assertEqual(lib_constants.FLOATINGIP_STATUS_ACTIVE, result)
|
||||
|
||||
def test_add_floating_ip_failure(self):
|
||||
ri = self._create_router(mock.MagicMock())
|
||||
ip = '15.1.2.3'
|
||||
fip = {'floating_ip_address': ip}
|
||||
result = self._test_add_floating_ip(ri, fip, True)
|
||||
ri.floating_ip_added_dist.assert_called_once_with(fip, ip + '/32')
|
||||
self.assertEqual(lib_constants.FLOATINGIP_STATUS_ERROR, result)
|
||||
|
||||
@mock.patch.object(router_info.RouterInfo, 'remove_floating_ip')
|
||||
def test_remove_floating_ip(self, super_remove_floating_ip):
|
||||
ri = self._create_router(mock.MagicMock())
|
||||
@ -694,14 +711,14 @@ class TestDvrRouterOperations(base.BaseTestCase):
|
||||
|
||||
def test_external_gateway_removed_ext_gw_port_and_fip(self):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
agent.conf.agent_mode = 'dvr'
|
||||
agent.conf.agent_mode = lib_constants.L3_AGENT_MODE_DVR_SNAT
|
||||
router = l3_test_common.prepare_router_data(num_internal_ports=2)
|
||||
router['gw_port_host'] = HOSTNAME
|
||||
self.mock_driver.unplug.reset_mock()
|
||||
|
||||
external_net_id = router['gw_port']['network_id']
|
||||
self._set_ri_kwargs(agent, router['id'], router)
|
||||
ri = dvr_router.DvrLocalRouter(HOSTNAME, **self.ri_kwargs)
|
||||
ri = dvr_edge_rtr.DvrEdgeRouter(HOSTNAME, **self.ri_kwargs)
|
||||
ri.remove_floating_ip = mock.Mock()
|
||||
agent._fetch_external_net_id = mock.Mock(return_value=external_net_id)
|
||||
ri.ex_gw_port = ri.router['gw_port']
|
||||
|
@ -0,0 +1,20 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Floating IPs associated with an unbound port with DVR routers will
|
||||
not be distributed, but will be centralized and implemented in the
|
||||
SNAT namespace of the Network node or ``dvr_snat`` node.
|
||||
Floating IPs associated with allowed_address_pair port IP and are
|
||||
bound to multiple active VMs with DVR routers will be implemented
|
||||
in the SNAT namespace in the Network node or ``dvr_snat`` node. This
|
||||
will address VRRP use cases.
|
||||
More information about this is captured in
|
||||
`bug 1583694 <https://bugs.launchpad.net/neutron/+bug/1583694>`__.
|
||||
issues:
|
||||
- |
|
||||
While the bound port Floating IPs are distributed, the unbound port
|
||||
Floating IPs are centralized.
|
||||
fixes:
|
||||
- |
|
||||
Allows the unbound port Floating IPs to be configured
|
||||
properly with DVR routers irrespective of its device_owner.
|
Loading…
Reference in New Issue
Block a user