if ri.router['distributed']:
# Special Handling for DVR - update FIP namespace
# and ri.namespace to handle DVR based FIP
- self.floating_ip_added_dist(ri, fip, ip_cidr)
+ ri.floating_ip_added_dist(fip, ip_cidr)
else:
# As GARP is processed in a distinct thread the call below
# won't raise an exception to be handled.
namespace=ri.ns_name,
ip=ip_cidr)
if ri.router['distributed']:
+ #TODO(Carl) Call this method on ri. Needs namespace work.
self.floating_ip_removed_dist(ri, ip_cidr)
def _get_router_cidrs(self, ri, device):
# kicks the FW Agent to add rules for the snat namespace
self.process_router_add(ri)
- def floating_ip_added_dist(self, ri, fip, fip_cidr):
- """Add floating IP to FIP namespace."""
- floating_ip = fip['floating_ip_address']
- fixed_ip = fip['fixed_ip_address']
- rule_pr = ri.fip_ns.allocate_rule_priority()
- ri.floating_ips_dict[floating_ip] = rule_pr
- fip_2_rtr_name = ri.fip_ns.get_int_device_name(ri.router_id)
- ip_rule = ip_lib.IpRule(self.root_helper, namespace=ri.ns_name)
- ip_rule.add(fixed_ip, dvr_fip_ns.FIP_RT_TBL, rule_pr)
- #Add routing rule in fip namespace
- fip_ns_name = ri.fip_ns.get_name()
- rtr_2_fip, _ = ri.rtr_fip_subnet.get_pair()
- device = ip_lib.IPDevice(fip_2_rtr_name, self.root_helper,
- namespace=fip_ns_name)
- device.route.add_route(fip_cidr, str(rtr_2_fip.ip))
- interface_name = (
- ri.fip_ns.get_ext_device_name(ri.fip_ns.agent_gateway_port['id']))
- ip_lib.send_garp_for_proxyarp(fip_ns_name,
- interface_name,
- floating_ip,
- self.conf.send_arp_for_ha,
- self.root_helper)
- # update internal structures
- ri.dist_fip_count = ri.dist_fip_count + 1
-
def floating_ip_removed_dist(self, ri, fip_cidr):
"""Remove floating IP from FIP namespace."""
- floating_ip = fip_cidr.split('/')[0]
- rtr_2_fip_name = ri.fip_ns.get_rtr_ext_device_name(ri.router_id)
- fip_2_rtr_name = ri.fip_ns.get_int_device_name(ri.router_id)
- if ri.rtr_fip_subnet is None:
- ri.rtr_fip_subnet = self.local_subnets.allocate(ri.router_id)
- rtr_2_fip, fip_2_rtr = ri.rtr_fip_subnet.get_pair()
- fip_ns_name = ri.fip_ns.get_name()
- if floating_ip in ri.floating_ips_dict:
- rule_pr = ri.floating_ips_dict[floating_ip]
- ip_rule = ip_lib.IpRule(self.root_helper, namespace=ri.ns_name)
- ip_rule.delete(floating_ip, dvr_fip_ns.FIP_RT_TBL, rule_pr)
- ri.fip_ns.deallocate_rule_priority(rule_pr)
- #TODO(rajeev): Handle else case - exception/log?
-
- device = ip_lib.IPDevice(fip_2_rtr_name, self.root_helper,
- namespace=fip_ns_name)
-
- device.route.delete_route(fip_cidr, str(rtr_2_fip.ip))
- # check if this is the last FIP for this router
- ri.dist_fip_count = ri.dist_fip_count - 1
- if ri.dist_fip_count == 0:
- #remove default route entry
- device = ip_lib.IPDevice(rtr_2_fip_name, self.root_helper,
- namespace=ri.ns_name)
- ns_ip = ip_lib.IPWrapper(self.root_helper, namespace=fip_ns_name)
- device.route.delete_gateway(str(fip_2_rtr.ip),
- table=dvr_fip_ns.FIP_RT_TBL)
- ri.fip_ns.local_subnets.release(ri.router_id)
- ri.rtr_fip_subnet = None
- ns_ip.del_veth(fip_2_rtr_name)
- is_last = ri.fip_ns.unsubscribe(ri.router_id)
- # clean up fip-namespace if this is the last FIP
- if is_last:
- self._destroy_fip_namespace(fip_ns_name)
+ is_last = ri.floating_ip_removed_dist(fip_cidr)
+ # clean up fip-namespace if this is the last FIP
+ if is_last:
+ self._destroy_fip_namespace(ri.fip_ns.get_name())
def _snat_redirect_add(self, ri, gateway, sn_port, sn_int):
"""Adds rules and routes for SNAT redirection."""
# License for the specific language governing permissions and limitations
# under the License.
+from neutron.agent.l3 import dvr_fip_ns
from neutron.agent.l3 import router_info as router
+from neutron.agent.linux import ip_lib
class DvrRouter(router.RouterInfo):
{'interface_name': interface_name})
self.iptables_manager.ipv4['nat'].add_rule(*rule)
self.iptables_manager.apply()
+
+ def floating_ip_added_dist(self, fip, fip_cidr):
+ """Add floating IP to FIP namespace."""
+ floating_ip = fip['floating_ip_address']
+ fixed_ip = fip['fixed_ip_address']
+ rule_pr = self.fip_ns.allocate_rule_priority()
+ self.floating_ips_dict[floating_ip] = rule_pr
+ fip_2_rtr_name = self.fip_ns.get_int_device_name(self.router_id)
+ ip_rule = ip_lib.IpRule(self.root_helper, namespace=self.ns_name)
+ ip_rule.add(fixed_ip, dvr_fip_ns.FIP_RT_TBL, rule_pr)
+ #Add routing rule in fip namespace
+ fip_ns_name = self.fip_ns.get_name()
+ rtr_2_fip, _ = self.rtr_fip_subnet.get_pair()
+ device = ip_lib.IPDevice(fip_2_rtr_name, self.root_helper,
+ namespace=fip_ns_name)
+ device.route.add_route(fip_cidr, str(rtr_2_fip.ip))
+ interface_name = (
+ self.fip_ns.get_ext_device_name(
+ self.fip_ns.agent_gateway_port['id']))
+ ip_lib.send_garp_for_proxyarp(fip_ns_name,
+ interface_name,
+ floating_ip,
+ self.agent_conf.send_arp_for_ha,
+ self.root_helper)
+ # update internal structures
+ self.dist_fip_count = self.dist_fip_count + 1
+
+ def floating_ip_removed_dist(self, fip_cidr):
+ """Remove floating IP from FIP namespace."""
+ floating_ip = fip_cidr.split('/')[0]
+ rtr_2_fip_name = self.fip_ns.get_rtr_ext_device_name(self.router_id)
+ fip_2_rtr_name = self.fip_ns.get_int_device_name(self.router_id)
+ if self.rtr_fip_subnet is None:
+ self.rtr_fip_subnet = self.local_subnets.allocate(self.router_id)
+
+ rtr_2_fip, fip_2_rtr = self.rtr_fip_subnet.get_pair()
+ fip_ns_name = self.fip_ns.get_name()
+ if floating_ip in self.floating_ips_dict:
+ rule_pr = self.floating_ips_dict[floating_ip]
+ ip_rule = ip_lib.IpRule(self.root_helper, namespace=self.ns_name)
+ ip_rule.delete(floating_ip, dvr_fip_ns.FIP_RT_TBL, rule_pr)
+ self.fip_ns.deallocate_rule_priority(rule_pr)
+ #TODO(rajeev): Handle else case - exception/log?
+
+ device = ip_lib.IPDevice(fip_2_rtr_name, self.root_helper,
+ namespace=fip_ns_name)
+
+ device.route.delete_route(fip_cidr, str(rtr_2_fip.ip))
+ # check if this is the last FIP for this router
+ self.dist_fip_count = self.dist_fip_count - 1
+ is_last = False
+ if self.dist_fip_count == 0:
+ #remove default route entry
+ device = ip_lib.IPDevice(rtr_2_fip_name,
+ self.root_helper,
+ namespace=self.ns_name)
+ ns_ip = ip_lib.IPWrapper(self.root_helper,
+ namespace=fip_ns_name)
+ device.route.delete_gateway(str(fip_2_rtr.ip),
+ table=dvr_fip_ns.FIP_RT_TBL)
+ self.fip_ns.local_subnets.release(self.router_id)
+ self.rtr_fip_subnet = None
+ ns_ip.del_veth(fip_2_rtr_name)
+ is_last = self.fip_ns.unsubscribe(self.router_id)
+ return is_last
--- /dev/null
+# Copyright (c) 2015 Openstack Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import mock
+import netaddr
+
+from neutron.agent.l3 import dvr_router
+from neutron.agent.l3 import link_local_allocator as lla
+from neutron.agent.linux import ip_lib
+from neutron.common import utils as common_utils
+from neutron.openstack.common import uuidutils
+from neutron.tests import base
+
+_uuid = uuidutils.generate_uuid
+FIP_PRI = 32768
+HOSTNAME = 'myhost'
+
+
+class TestDvrRouterOperations(base.BaseTestCase):
+ def setUp(self):
+ super(TestDvrRouterOperations, self).setUp()
+
+ def _create_router(self, router, **kwargs):
+ agent_conf = mock.Mock()
+ return dvr_router.DvrRouter(mock.sentinel.router_id,
+ router,
+ mock.sentinel.root_helper,
+ agent_conf,
+ mock.sentinel.interface_driver,
+ **kwargs)
+
+ @mock.patch.object(ip_lib, 'send_garp_for_proxyarp')
+ @mock.patch.object(ip_lib, 'IPDevice')
+ @mock.patch.object(ip_lib, 'IpRule')
+ def test_floating_ip_added_dist(self, mIpRule, mIPDevice, mock_arp):
+ router = mock.MagicMock()
+ ri = self._create_router(router)
+ ext_net_id = _uuid()
+ agent_gw_port = {'fixed_ips': [{'ip_address': '20.0.0.30',
+ 'subnet_id': _uuid()}],
+ 'subnet': {'gateway_ip': '20.0.0.1'},
+ 'id': _uuid(),
+ 'network_id': ext_net_id,
+ 'mac_address': 'ca:fe:de:ad:be:ef',
+ 'ip_cidr': '20.0.0.30/24'}
+
+ fip = {'id': _uuid(),
+ 'host': HOSTNAME,
+ 'floating_ip_address': '15.1.2.3',
+ 'fixed_ip_address': '192.168.0.1',
+ 'floating_network_id': ext_net_id,
+ 'port_id': _uuid()}
+ ri.fip_ns = mock.Mock()
+ ri.fip_ns.agent_gateway_port = agent_gw_port
+ ri.fip_ns.allocate_rule_priority.return_value = FIP_PRI
+ ri.rtr_fip_subnet = lla.LinkLocalAddressPair('169.254.30.42/31')
+ ri.dist_fip_count = 0
+ ip_cidr = common_utils.ip_to_cidr(fip['floating_ip_address'])
+ ri.floating_ip_added_dist(fip, ip_cidr)
+ mIpRule().add.assert_called_with('192.168.0.1', 16, FIP_PRI)
+ self.assertEqual(1, ri.dist_fip_count)
+ # TODO(mrsmith): add more asserts
+
+ @mock.patch.object(ip_lib, 'IPWrapper')
+ @mock.patch.object(ip_lib, 'IPDevice')
+ @mock.patch.object(ip_lib, 'IpRule')
+ def test_floating_ip_removed_dist(self, mIpRule, mIPDevice, mIPWrapper):
+ router = mock.MagicMock()
+ ri = self._create_router(router)
+
+ agent_gw_port = {'fixed_ips': [{'ip_address': '20.0.0.30',
+ 'subnet_id': _uuid()}],
+ 'subnet': {'gateway_ip': '20.0.0.1'},
+ 'id': _uuid(),
+ 'network_id': _uuid(),
+ 'mac_address': 'ca:fe:de:ad:be:ef',
+ 'ip_cidr': '20.0.0.30/24'}
+ fip_cidr = '11.22.33.44/24'
+
+ ri.dist_fip_count = 2
+ ri.fip_ns = mock.Mock()
+ ri.fip_ns.get_name.return_value = 'fip_ns_name'
+ ri.floating_ips_dict['11.22.33.44'] = FIP_PRI
+ ri.fip_2_rtr = '11.22.33.42'
+ ri.rtr_2_fip = '11.22.33.40'
+ ri.fip_ns.agent_gateway_port = agent_gw_port
+ s = lla.LinkLocalAddressPair('169.254.30.42/31')
+ ri.rtr_fip_subnet = s
+ ri.floating_ip_removed_dist(fip_cidr)
+ mIpRule().delete.assert_called_with(
+ str(netaddr.IPNetwork(fip_cidr).ip), 16, FIP_PRI)
+ mIPDevice().route.delete_route.assert_called_with(fip_cidr, str(s.ip))
+ self.assertFalse(ri.fip_ns.unsubscribe.called)
+
+ ri.dist_fip_count = 1
+ ri.rtr_fip_subnet = lla.LinkLocalAddressPair('15.1.2.3/32')
+ _, fip_to_rtr = ri.rtr_fip_subnet.get_pair()
+ ri.floating_ip_removed_dist(fip_cidr)
+ mIPWrapper().del_veth.assert_called_once_with(
+ ri.fip_ns.get_int_device_name(router['id']))
+ mIPDevice().route.delete_gateway.assert_called_once_with(
+ str(fip_to_rtr.ip), table=16)
+ ri.fip_ns.unsubscribe.assert_called_once_with(ri.router_id)
from neutron.common import config as base_config
from neutron.common import constants as l3_constants
from neutron.common import exceptions as n_exc
-from neutron.common import utils as common_utils
from neutron.i18n import _LE
from neutron.openstack.common import log
from neutron.openstack.common import uuidutils
self.assertEqual(self.mock_driver.plug.call_count, 3)
self.assertEqual(self.mock_driver.init_l3.call_count, 3)
- def test_floating_ip_added_dist(self):
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
- router = prepare_router_data()
- ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
- ext_net_id = _uuid()
- agent_gw_port = {'fixed_ips': [{'ip_address': '20.0.0.30',
- 'subnet_id': _uuid()}],
- 'subnet': {'gateway_ip': '20.0.0.1'},
- 'id': _uuid(),
- 'network_id': ext_net_id,
- 'mac_address': 'ca:fe:de:ad:be:ef',
- 'ip_cidr': '20.0.0.30/24'}
-
- fip = {'id': _uuid(),
- 'host': HOSTNAME,
- 'floating_ip_address': '15.1.2.3',
- 'fixed_ip_address': '192.168.0.1',
- 'floating_network_id': ext_net_id,
- 'port_id': _uuid()}
- ri.fip_ns = agent.get_fip_ns(ext_net_id)
- ri.fip_ns.agent_gateway_port = agent_gw_port
- ri.rtr_fip_subnet = lla.LinkLocalAddressPair('169.254.30.42/31')
- ri.dist_fip_count = 0
- ip_cidr = common_utils.ip_to_cidr(fip['floating_ip_address'])
- agent.floating_ip_added_dist(ri, fip, ip_cidr)
- self.mock_rule.add.assert_called_with('192.168.0.1', 16, FIP_PRI)
- # TODO(mrsmith): add more asserts
-
- @mock.patch.object(lla.LinkLocalAllocator, '_write')
- def test_floating_ip_removed_dist(self, write):
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
- router = prepare_router_data()
- agent_gw_port = {'fixed_ips': [{'ip_address': '20.0.0.30',
- 'subnet_id': _uuid()}],
- 'subnet': {'gateway_ip': '20.0.0.1'},
- 'id': _uuid(),
- 'network_id': _uuid(),
- 'mac_address': 'ca:fe:de:ad:be:ef',
- 'ip_cidr': '20.0.0.30/24'}
- fip_cidr = '11.22.33.44/24'
-
- ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
- ri.dist_fip_count = 2
- ri.fip_ns = agent.get_fip_ns(agent._fetch_external_net_id())
- ri.fip_ns.unsubscribe = mock.Mock()
- ri.floating_ips_dict['11.22.33.44'] = FIP_PRI
- ri.fip_2_rtr = '11.22.33.42'
- ri.rtr_2_fip = '11.22.33.40'
- agent.agent_gateway_port = agent_gw_port
- s = lla.LinkLocalAddressPair('169.254.30.42/31')
- ri.rtr_fip_subnet = s
- agent.floating_ip_removed_dist(ri, fip_cidr)
- floating_ip = fip_cidr.split('/')[0]
- self.mock_rule.delete.assert_called_with(floating_ip, 16, FIP_PRI)
- self.mock_ip_dev.route.delete_route.assert_called_with(fip_cidr,
- str(s.ip))
- self.assertFalse(ri.fip_ns.unsubscribe.called)
-
- with mock.patch.object(agent, '_destroy_fip_namespace') as f:
- ri.dist_fip_count = 1
- fip_ns_name = ri.fip_ns.get_name()
- ri.rtr_fip_subnet = ri.fip_ns.local_subnets.allocate(ri.router_id)
- _, fip_to_rtr = ri.rtr_fip_subnet.get_pair()
- agent.floating_ip_removed_dist(ri, fip_cidr)
- self.mock_ip.del_veth.assert_called_once_with(
- ri.fip_ns.get_int_device_name(router['id']))
- self.mock_ip_dev.route.delete_gateway.assert_called_once_with(
- str(fip_to_rtr.ip), table=16)
- f.assert_called_once_with(fip_ns_name)
- ri.fip_ns.unsubscribe.assert_called_once_with(ri.router_id)
-
def test_get_service_plugin_list(self):
service_plugins = [p_const.L3_ROUTER_NAT]
self.plugin_api.get_service_plugin_list.return_value = service_plugins