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)
+ ri.floating_ip_removed_dist(ip_cidr)
def _get_router_cidrs(self, ri, device):
if ri.is_ha:
import binascii
import netaddr
+import weakref
from neutron.agent.l3 import dvr_fip_ns
from neutron.agent.linux import ip_lib
class AgentMixin(object):
def __init__(self, host):
# dvr data
- self._fip_namespaces = {}
+ self._fip_namespaces = weakref.WeakValueDictionary()
super(AgentMixin, self).__init__(host)
def get_fip_ns(self, ext_net_id):
# convert these to string like this so I preserved that.
ext_net_id = str(ext_net_id)
- if ext_net_id not in self._fip_namespaces:
- fip_ns = dvr_fip_ns.FipNamespace(ext_net_id,
- self.conf,
- self.driver,
- self.root_helper,
- self.use_ipv6)
- self._fip_namespaces[ext_net_id] = fip_ns
+ fip_ns = self._fip_namespaces.get(ext_net_id)
+ if fip_ns and not fip_ns.destroyed:
+ return fip_ns
- return self._fip_namespaces[ext_net_id]
+ fip_ns = dvr_fip_ns.FipNamespace(ext_net_id,
+ self.conf,
+ self.driver,
+ self.root_helper,
+ self.use_ipv6)
+ self._fip_namespaces[ext_net_id] = fip_ns
+
+ return fip_ns
def _destroy_snat_namespace(self, ns):
ns_ip = ip_lib.IPWrapper(self.root_helper, namespace=ns)
def _destroy_fip_namespace(self, ns):
ex_net_id = ns[len(dvr_fip_ns.FIP_NS_PREFIX):]
fip_ns = self.get_fip_ns(ex_net_id)
- del self._fip_namespaces[ex_net_id]
fip_ns.destroy()
def _set_subnet_arp_info(self, ri, port):
# kicks the FW Agent to add rules for the snat namespace
self.process_router_add(ri)
- def floating_ip_removed_dist(self, ri, fip_cidr):
- """Remove floating IP from FIP namespace."""
- 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."""
try:
use_ipv6=self.use_ipv6)
path = os.path.join(agent_conf.state_path, 'fip-linklocal-networks')
self.local_subnets = lla.LinkLocalAllocator(path, FIP_LL_SUBNET)
+ self.destroyed = False
def get_name(self):
return (FIP_NS_PREFIX + self._ext_net_id)
self._iptables_manager.apply()
def destroy(self):
+ self.destroyed = True
ns = self.get_name()
# TODO(carl) Reconcile this with mlavelle's namespace work
# TODO(carl) mlavelle's work has self.ip_wrapper
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.rtr_fip_subnet = None
ns_ip.del_veth(fip_2_rtr_name)
is_last = self.fip_ns.unsubscribe(self.router_id)
- return is_last
+ if is_last:
+ # TODO(Carl) I can't help but think that another router could
+ # come in and want to start using this namespace while this is
+ # destroying it. The two could end up conflicting on
+ # creating/destroying interfaces and such. I think I'd like a
+ # semaphore to sync creation/deletion of this namespace.
+ self.fip_ns.destroy()
+ self.fip_ns = None
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()
+ fip_ns = ri.fip_ns
+
ri.floating_ip_removed_dist(fip_cidr)
+
+ self.assertTrue(fip_ns.destroyed)
mIPWrapper().del_veth.assert_called_once_with(
- ri.fip_ns.get_int_device_name(router['id']))
+ 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)
+ fip_ns.unsubscribe.assert_called_once_with(ri.router_id)
{'cidr': '19.4.4.1/24'}]
self.device_exists.return_value = True
+ fip_ns = ri.fip_ns
agent.external_gateway_removed(
ri, ri.ex_gw_port,
agent.get_external_device_name(ri.ex_gw_port['id']))
self.mock_ip.del_veth.assert_called_once_with(
- ri.fip_ns.get_int_device_name(ri.router['id']))
+ fip_ns.get_int_device_name(ri.router['id']))
self.mock_ip_dev.route.delete_gateway.assert_called_once_with(
str(fip_to_rtr.ip), table=dvr_fip_ns.FIP_RT_TBL)
self.assertEqual(ri.dist_fip_count, 0)
- self.assertFalse(ri.fip_ns.has_subscribers())
+ self.assertFalse(fip_ns.has_subscribers())
self.assertEqual(self.mock_driver.unplug.call_count, 1)
- self.assertIsNone(ri.fip_ns.agent_gateway_port)
- self.mock_ip.netns.delete.assert_called_once_with(ri.fip_ns.get_name())
+ self.assertIsNone(fip_ns.agent_gateway_port)
+ self.assertTrue(fip_ns.destroyed)
+ self.mock_ip.netns.delete.assert_called_once_with(fip_ns.get_name())
self.assertFalse(nat.add_rule.called)
nat.clear_rules_by_tag.assert_called_once_with('floating_ip')