from neutron.agent.common import config
from neutron.agent.l3 import dvr
+from neutron.agent.l3 import dvr_fip_ns
from neutron.agent.l3 import dvr_router
from neutron.agent.l3 import event_observers
from neutron.agent.l3 import ha
def _destroy_namespace(self, ns):
if ns.startswith(NS_PREFIX):
self._destroy_router_namespace(ns)
- elif ns.startswith(dvr.FIP_NS_PREFIX):
+ elif ns.startswith(dvr_fip_ns.FIP_NS_PREFIX):
self._destroy_fip_namespace(ns)
elif ns.startswith(dvr.SNAT_NS_PREFIX):
self._destroy_snat_namespace(ns)
# device is on default bridge
self.driver.unplug(d.name, namespace=ns,
prefix=INTERNAL_DEV_PREFIX)
- elif d.name.startswith(dvr.ROUTER_2_FIP_DEV_PREFIX):
+ elif d.name.startswith(dvr_fip_ns.ROUTER_2_FIP_DEV_PREFIX):
ns_ip.del_veth(d.name)
elif d.name.startswith(EXTERNAL_DEV_PREFIX):
self.driver.unplug(d.name,
# TODO(mrsmith) - we shouldn't need to check here
if 'distributed' not in ri.router:
ri.router['distributed'] = False
- self.scan_fip_ports(ri)
+ ex_gw_port = self._get_ex_gw_port(ri)
+ if ri.router.get('distributed') and ex_gw_port:
+ ri.fip_ns = self.get_fip_ns(ex_gw_port['network_id'])
+ ri.fip_ns.scan_fip_ports(ri)
self._process_internal_ports(ri)
self._process_external(ri)
# Process static routes for router
self._process_ha_router(ri)
# Update ex_gw_port and enable_snat on the router info cache
- ri.ex_gw_port = self._get_ex_gw_port(ri)
+ ri.ex_gw_port = ex_gw_port
ri.snat_ports = ri.router.get(l3_constants.SNAT_ROUTER_INTF_KEY, [])
ri.enable_snat = ri.router.get('enable_snat')
def create_dvr_fip_interfaces(self, ri, ex_gw_port):
floating_ips = self.get_floating_ips(ri)
if floating_ips:
- is_first = self._fip_ns_subscribe(ri.router_id)
+ is_first = ri.fip_ns.subscribe(ri.router_id)
if is_first:
- self._create_agent_gateway_port(ri, floating_ips[0]
- ['floating_network_id'])
-
- if self.agent_gateway_port and floating_ips:
- fip_net_id = floating_ips[0]['floating_network_id']
- self.create_rtr_2_fip_link(ri, fip_net_id)
+ agent_gateway_port = (
+ self.plugin_rpc.get_agent_gateway_port(
+ self.context, ex_gw_port['network_id']))
+ if 'subnet' not in agent_gateway_port:
+ LOG.error(_LE('Missing subnet/agent_gateway_port'))
+ else:
+ self._set_subnet_info(agent_gateway_port)
+ ri.fip_ns.create_gateway_port(agent_gateway_port)
+
+ if ri.fip_ns.agent_gateway_port and floating_ips:
+ if ri.dist_fip_count == 0:
+ ri.fip_ns.create_rtr_2_fip_link(ri)
+
+ # kicks the FW Agent to add rules for the IR namespace if
+ # configured
+ self.process_router_add(ri)
def _get_external_device_interface_name(self, ri, ex_gw_port):
if ri.router['distributed']:
- fip_int = self.get_fip_int_device_name(ri.router_id)
- # TODO(mrsmith) refactor for multiple ext nets
- fip_ns = self.get_fip_ns_name(str(self._fetch_external_net_id()))
-
+ fip_int = ri.fip_ns.get_int_device_name(ri.router_id)
if ip_lib.device_exists(fip_int,
root_helper=self.root_helper,
- namespace=fip_ns):
- return self.get_rtr_int_device_name(ri.router_id)
+ namespace=ri.fip_ns.get_name()):
+ return ri.fip_ns.get_rtr_ext_device_name(ri.router_id)
else:
return self.get_external_device_name(ex_gw_port['id'])
import binascii
import netaddr
-import os
-from neutron.agent.l3 import link_local_allocator as lla
+from neutron.agent.l3 import dvr_fip_ns
from neutron.agent.linux import ip_lib
from neutron.agent.linux import iptables_manager
from neutron.common import constants as l3_constants
-from neutron.common import utils as common_utils
from neutron.i18n import _LE
from neutron.openstack.common import log as logging
LOG = logging.getLogger(__name__)
SNAT_INT_DEV_PREFIX = 'sg-'
-FIP_EXT_DEV_PREFIX = 'fg-'
-FIP_NS_PREFIX = 'fip-'
SNAT_NS_PREFIX = 'snat-'
-FIP_2_ROUTER_DEV_PREFIX = 'fpr-'
-ROUTER_2_FIP_DEV_PREFIX = 'rfp-'
-FIP_LL_SUBNET = '169.254.30.0/23'
-# Rule priority range for FIPs
-FIP_PR_START = 32768
-FIP_PR_END = FIP_PR_START + 40000
-# Route Table index for FIPs
-FIP_RT_TBL = 16
# xor-folding mask used for IPv6 rule index
MASK_30 = 0x3fffffff
class AgentMixin(object):
def __init__(self, host):
# dvr data
- self.agent_gateway_port = None
- self.fip_ns_subscribers = set()
- self.local_subnets = lla.LinkLocalAllocator(
- os.path.join(self.conf.state_path, 'fip-linklocal-networks'),
- FIP_LL_SUBNET)
- self.fip_priorities = set(range(FIP_PR_START,
- FIP_PR_END))
-
+ self._fip_namespaces = {}
super(AgentMixin, self).__init__(host)
- def _fip_ns_subscribe(self, router_id):
- is_first = (len(self.fip_ns_subscribers) == 0)
- self.fip_ns_subscribers.add(router_id)
- return is_first
+ def get_fip_ns(self, ext_net_id):
+ # TODO(Carl) is this necessary? Code that this replaced was careful to
+ # 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
- def _fip_ns_unsubscribe(self, router_id):
- self.fip_ns_subscribers.discard(router_id)
- return len(self.fip_ns_subscribers) == 0
+ return self._fip_namespaces[ext_net_id]
def _destroy_snat_namespace(self, ns):
ns_ip = ip_lib.IPWrapper(self.root_helper, namespace=ns)
self._delete_namespace(ns_ip, ns)
def _destroy_fip_namespace(self, ns):
- ns_ip = ip_lib.IPWrapper(self.root_helper, namespace=ns)
- for d in ns_ip.get_devices(exclude_loopback=True):
- if d.name.startswith(FIP_2_ROUTER_DEV_PREFIX):
- # internal link between IRs and FIP NS
- ns_ip.del_veth(d.name)
- elif d.name.startswith(FIP_EXT_DEV_PREFIX):
- # single port from FIP NS to br-ext
- # TODO(carl) Where does the port get deleted?
- LOG.debug('DVR: unplug: %s', d.name)
- self.driver.unplug(d.name,
- bridge=self.conf.external_network_bridge,
- namespace=ns,
- prefix=FIP_EXT_DEV_PREFIX)
- LOG.debug('DVR: destroy fip ns: %s', ns)
- # TODO(mrsmith): add LOG warn if fip count != 0
- if self.conf.router_delete_namespaces:
- self._delete_namespace(ns_ip, ns)
- self.agent_gateway_port = None
+ 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):
"""Set ARP info retrieved from Plugin for existing ports."""
if f['subnet_id'] == subnet_id:
return port
- def scan_fip_ports(self, ri):
- # don't scan if not dvr or count is not None
- if not ri.router.get('distributed') or ri.dist_fip_count is not None:
- return
-
- # scan system for any existing fip ports
- ri.dist_fip_count = 0
- rtr_2_fip_interface = self.get_rtr_int_device_name(ri.router_id)
- if ip_lib.device_exists(rtr_2_fip_interface,
- root_helper=self.root_helper,
- namespace=ri.ns_name):
- device = ip_lib.IPDevice(rtr_2_fip_interface, self.root_helper,
- namespace=ri.ns_name)
- existing_cidrs = [addr['cidr'] for addr in device.addr.list()]
- fip_cidrs = [c for c in existing_cidrs if
- common_utils.is_cidr_host(c)]
- ri.dist_fip_count = len(fip_cidrs)
-
- def get_fip_ext_device_name(self, port_id):
- return (FIP_EXT_DEV_PREFIX +
- port_id)[:self.driver.DEV_NAME_LEN]
-
- def get_rtr_int_device_name(self, router_id):
- return (ROUTER_2_FIP_DEV_PREFIX +
- router_id)[:self.driver.DEV_NAME_LEN]
-
- def get_fip_int_device_name(self, router_id):
- return (FIP_2_ROUTER_DEV_PREFIX +
- router_id)[:self.driver.DEV_NAME_LEN]
-
def get_snat_int_device_name(self, port_id):
return (SNAT_INT_DEV_PREFIX +
port_id)[:self.driver.DEV_NAME_LEN]
- def get_fip_ns_name(self, ext_net_id):
- return (FIP_NS_PREFIX + ext_net_id)
-
def get_snat_ns_name(self, router_id):
return (SNAT_NS_PREFIX + router_id)
else:
LOG.error(_LE('DVR: no map match_port found!'))
- def internal_ns_interface_added(self, ip_cidr,
- interface_name, ns_name):
- ip_wrapper = ip_lib.IPWrapper(self.root_helper, namespace=ns_name)
- ip_wrapper.netns.execute(['ip', 'addr', 'add',
- ip_cidr, 'dev', interface_name])
-
- def _handle_router_fip_nat_rules(self, ri, interface_name, action):
- """Configures NAT rules for Floating IPs for DVR.
-
- Remove all the rules. This is safe because if
- use_namespaces is set as False then the agent can
- only configure one router, otherwise each router's
- NAT rules will be in their own namespace.
- """
- ri.iptables_manager.ipv4['nat'].empty_chain('POSTROUTING')
- ri.iptables_manager.ipv4['nat'].empty_chain('snat')
-
- # Add back the jump to float-snat
- ri.iptables_manager.ipv4['nat'].add_rule('snat', '-j $float-snat')
-
- # And add them back if the action is add_rules
- if action == 'add_rules' and interface_name:
- rule = ('POSTROUTING', '! -i %(interface_name)s '
- '! -o %(interface_name)s -m conntrack ! '
- '--ctstate DNAT -j ACCEPT' %
- {'interface_name': interface_name})
- ri.iptables_manager.ipv4['nat'].add_rule(*rule)
- ri.iptables_manager.apply()
-
def _create_dvr_gateway(self, ri, ex_gw_port, gw_interface_name,
snat_ports):
"""Create SNAT namespace."""
# kicks the FW Agent to add rules for the snat namespace
self.process_router_add(ri)
- def agent_gateway_added(self, ns_name, ex_gw_port,
- interface_name):
- """Add Floating IP gateway port to FIP namespace."""
- if not ip_lib.device_exists(interface_name,
- root_helper=self.root_helper,
- namespace=ns_name):
- self.driver.plug(ex_gw_port['network_id'],
- ex_gw_port['id'], interface_name,
- ex_gw_port['mac_address'],
- bridge=self.conf.external_network_bridge,
- namespace=ns_name,
- prefix=FIP_EXT_DEV_PREFIX)
-
- self.driver.init_l3(interface_name, [ex_gw_port['ip_cidr']],
- namespace=ns_name)
- ip_address = ex_gw_port['ip_cidr'].split('/')[0]
- ip_lib.send_gratuitous_arp(ns_name,
- interface_name,
- ip_address,
- self.conf.send_arp_for_ha,
- self.root_helper)
-
- gw_ip = ex_gw_port['subnet']['gateway_ip']
- if gw_ip:
- ipd = ip_lib.IPDevice(interface_name, self.root_helper,
- namespace=ns_name)
- ipd.route.add_gateway(gw_ip)
-
- cmd = ['sysctl', '-w', 'net.ipv4.conf.%s.proxy_arp=1' % interface_name]
- ip_wrapper = ip_lib.IPWrapper(self.root_helper, namespace=ns_name)
- ip_wrapper.netns.execute(cmd, check_exit_code=False)
-
- def _create_agent_gateway_port(self, ri, network_id):
- """Create Floating IP gateway port.
-
- Request port creation from Plugin then creates
- Floating IP namespace and adds gateway port.
- """
- self.agent_gateway_port = (
- self.plugin_rpc.get_agent_gateway_port(
- self.context, network_id))
- if 'subnet' not in self.agent_gateway_port:
- LOG.error(_LE('Missing subnet/agent_gateway_port'))
- return
- self._set_subnet_info(self.agent_gateway_port)
-
- # add fip-namespace and agent_gateway_port
- fip_ns_name = (
- self.get_fip_ns_name(str(network_id)))
- self._create_namespace(fip_ns_name)
- ri.fip_iptables_manager = iptables_manager.IptablesManager(
- root_helper=self.root_helper, namespace=fip_ns_name,
- use_ipv6=self.use_ipv6)
- # no connection tracking needed in fip namespace
- ri.fip_iptables_manager.ipv4['raw'].add_rule('PREROUTING',
- '-j CT --notrack')
- ri.fip_iptables_manager.apply()
- interface_name = (
- self.get_fip_ext_device_name(self.agent_gateway_port['id']))
- self.agent_gateway_added(fip_ns_name, self.agent_gateway_port,
- interface_name)
-
- def create_rtr_2_fip_link(self, ri, network_id):
- """Create interface between router and Floating IP namespace."""
- rtr_2_fip_name = self.get_rtr_int_device_name(ri.router_id)
- fip_2_rtr_name = self.get_fip_int_device_name(ri.router_id)
- fip_ns_name = self.get_fip_ns_name(str(network_id))
-
- # add link local IP to interface
- 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()
- ip_wrapper = ip_lib.IPWrapper(self.root_helper,
- namespace=ri.ns_name)
- if not ip_lib.device_exists(rtr_2_fip_name, self.root_helper,
- namespace=ri.ns_name):
- int_dev = ip_wrapper.add_veth(rtr_2_fip_name,
- fip_2_rtr_name, fip_ns_name)
- self.internal_ns_interface_added(str(rtr_2_fip),
- rtr_2_fip_name, ri.ns_name)
- self.internal_ns_interface_added(str(fip_2_rtr),
- fip_2_rtr_name, fip_ns_name)
- int_dev[0].link.set_up()
- int_dev[1].link.set_up()
- # add default route for the link local interface
- device = ip_lib.IPDevice(rtr_2_fip_name, self.root_helper,
- namespace=ri.ns_name)
- device.route.add_gateway(str(fip_2_rtr.ip), table=FIP_RT_TBL)
- #setup the NAT rules and chains
- self._handle_router_fip_nat_rules(ri, rtr_2_fip_name, 'add_rules')
- # kicks the FW Agent to add rules for the IR namespace if configured
- 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 = self.fip_priorities.pop()
+ rule_pr = ri.fip_ns.allocate_rule_priority()
ri.floating_ips_dict[floating_ip] = rule_pr
- fip_2_rtr_name = self.get_fip_int_device_name(ri.router_id)
+ 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, FIP_RT_TBL, rule_pr)
+ ip_rule.add(fixed_ip, dvr_fip_ns.FIP_RT_TBL, rule_pr)
#Add routing rule in fip namespace
- fip_ns_name = self.get_fip_ns_name(str(fip['floating_network_id']))
+ 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 = (
- self.get_fip_ext_device_name(self.agent_gateway_port['id']))
+ 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,
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 = self.get_rtr_int_device_name(ri.router_id)
- fip_2_rtr_name = self.get_fip_int_device_name(ri.router_id)
+ 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 = self.get_fip_ns_name(str(self._fetch_external_net_id()))
+ 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, FIP_RT_TBL, rule_pr)
- self.fip_priorities.add(rule_pr)
+ 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=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=FIP_RT_TBL)
- self.local_subnets.release(ri.router_id)
+ 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 = self._fip_ns_unsubscribe(ri.router_id)
+ 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)
--- /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 netaddr
+import os
+
+from neutron.agent.l3 import link_local_allocator as lla
+from neutron.agent.linux import ip_lib
+from neutron.agent.linux import iptables_manager
+from neutron.common import utils as common_utils
+from neutron.i18n import _LE
+from neutron.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+FIP_NS_PREFIX = 'fip-'
+FIP_EXT_DEV_PREFIX = 'fg-'
+FIP_2_ROUTER_DEV_PREFIX = 'fpr-'
+ROUTER_2_FIP_DEV_PREFIX = 'rfp-'
+# Route Table index for FIPs
+FIP_RT_TBL = 16
+FIP_LL_SUBNET = '169.254.30.0/23'
+# Rule priority range for FIPs
+FIP_PR_START = 32768
+FIP_PR_END = FIP_PR_START + 40000
+
+
+class FipNamespace(object):
+ def __init__(self, ext_net_id, agent_conf, driver, root_helper, use_ipv6):
+ self._ext_net_id = ext_net_id
+ self.agent_conf = agent_conf
+ self.driver = driver
+ self.root_helper = root_helper
+ self.use_ipv6 = use_ipv6
+ self.agent_gateway_port = None
+ self._subscribers = set()
+ self._rule_priorities = set(range(FIP_PR_START, FIP_PR_END))
+ self._iptables_manager = iptables_manager.IptablesManager(
+ root_helper=self.root_helper,
+ namespace=self.get_name(),
+ 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)
+
+ def get_name(self):
+ return (FIP_NS_PREFIX + self._ext_net_id)
+
+ def get_ext_device_name(self, port_id):
+ return (FIP_EXT_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
+
+ def get_int_device_name(self, router_id):
+ return (FIP_2_ROUTER_DEV_PREFIX + router_id)[:self.driver.DEV_NAME_LEN]
+
+ def get_rtr_ext_device_name(self, router_id):
+ return (ROUTER_2_FIP_DEV_PREFIX + router_id)[:self.driver.DEV_NAME_LEN]
+
+ def has_subscribers(self):
+ return len(self._subscribers) != 0
+
+ def subscribe(self, router_id):
+ is_first = not self.has_subscribers()
+ self._subscribers.add(router_id)
+ return is_first
+
+ def unsubscribe(self, router_id):
+ self._subscribers.discard(router_id)
+ return not self.has_subscribers()
+
+ def allocate_rule_priority(self):
+ return self._rule_priorities.pop()
+
+ def deallocate_rule_priority(self, rule_pr):
+ self._rule_priorities.add(rule_pr)
+
+ def _gateway_added(self, ex_gw_port, interface_name):
+ """Add Floating IP gateway port."""
+ ns_name = self.get_name()
+ if not ip_lib.device_exists(interface_name,
+ root_helper=self.root_helper,
+ namespace=ns_name):
+ self.driver.plug(ex_gw_port['network_id'],
+ ex_gw_port['id'],
+ interface_name,
+ ex_gw_port['mac_address'],
+ bridge=self.agent_conf.external_network_bridge,
+ namespace=ns_name,
+ prefix=FIP_EXT_DEV_PREFIX)
+
+ self.driver.init_l3(interface_name,
+ [ex_gw_port['ip_cidr']],
+ namespace=ns_name)
+
+ ip_address = str(netaddr.IPNetwork(ex_gw_port['ip_cidr']).ip)
+ ip_lib.send_gratuitous_arp(ns_name,
+ interface_name,
+ ip_address,
+ self.agent_conf.send_arp_for_ha,
+ self.root_helper)
+
+ gw_ip = ex_gw_port['subnet']['gateway_ip']
+ if gw_ip:
+ ipd = ip_lib.IPDevice(interface_name,
+ self.root_helper,
+ namespace=ns_name)
+ ipd.route.add_gateway(gw_ip)
+
+ cmd = ['sysctl', '-w', 'net.ipv4.conf.%s.proxy_arp=1' % interface_name]
+ # TODO(Carl) mlavelle's work has self.ip_wrapper
+ ip_wrapper = ip_lib.IPWrapper(self.root_helper, namespace=ns_name)
+ ip_wrapper.netns.execute(cmd, check_exit_code=False)
+
+ def create(self):
+ # TODO(Carl) Get this functionality from mlavelle's namespace baseclass
+ ip_wrapper_root = ip_lib.IPWrapper(self.root_helper)
+ ip_wrapper = ip_wrapper_root.ensure_namespace(self.get_name())
+ ip_wrapper.netns.execute(['sysctl', '-w', 'net.ipv4.ip_forward=1'])
+ if self.use_ipv6:
+ ip_wrapper.netns.execute(['sysctl', '-w',
+ 'net.ipv6.conf.all.forwarding=1'])
+
+ # no connection tracking needed in fip namespace
+ self._iptables_manager.ipv4['raw'].add_rule('PREROUTING',
+ '-j CT --notrack')
+ self._iptables_manager.apply()
+
+ def destroy(self):
+ ns = self.get_name()
+ # TODO(carl) Reconcile this with mlavelle's namespace work
+ # TODO(carl) mlavelle's work has self.ip_wrapper
+ ip_wrapper = ip_lib.IPWrapper(self.root_helper, namespace=ns)
+ for d in ip_wrapper.get_devices(exclude_loopback=True):
+ if d.name.startswith(FIP_2_ROUTER_DEV_PREFIX):
+ # internal link between IRs and FIP NS
+ ip_wrapper.del_veth(d.name)
+ elif d.name.startswith(FIP_EXT_DEV_PREFIX):
+ # single port from FIP NS to br-ext
+ # TODO(carl) Where does the port get deleted?
+ LOG.debug('DVR: unplug: %s', d.name)
+ ext_net_bridge = self.agent_conf.external_network_bridge
+ self.driver.unplug(d.name,
+ bridge=ext_net_bridge,
+ namespace=ns,
+ prefix=FIP_EXT_DEV_PREFIX)
+ LOG.debug('DVR: destroy fip ns: %s', ns)
+ # TODO(mrsmith): add LOG warn if fip count != 0
+ if self.agent_conf.router_delete_namespaces:
+ try:
+ ip_wrapper.netns.delete(ns)
+ except RuntimeError:
+ LOG.exception(_LE('Failed trying to delete namespace: %s'), ns)
+
+ self.agent_gateway_port = None
+
+ def create_gateway_port(self, agent_gateway_port):
+ """Create Floating IP gateway port.
+
+ Request port creation from Plugin then creates
+ Floating IP namespace and adds gateway port.
+ """
+ self.agent_gateway_port = agent_gateway_port
+
+ # add fip-namespace and agent_gateway_port
+ self.create()
+
+ iface_name = self.get_ext_device_name(agent_gateway_port['id'])
+ self._gateway_added(agent_gateway_port, iface_name)
+
+ def _internal_ns_interface_added(self, ip_cidr,
+ interface_name, ns_name):
+ ip_wrapper = ip_lib.IPWrapper(self.root_helper, namespace=ns_name)
+ ip_wrapper.netns.execute(['ip', 'addr', 'add',
+ ip_cidr, 'dev', interface_name])
+
+ def create_rtr_2_fip_link(self, ri):
+ """Create interface between router and Floating IP namespace."""
+ rtr_2_fip_name = self.get_rtr_ext_device_name(ri.router_id)
+ fip_2_rtr_name = self.get_int_device_name(ri.router_id)
+ fip_ns_name = self.get_name()
+
+ # add link local IP to interface
+ 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()
+ ip_wrapper = ip_lib.IPWrapper(self.root_helper,
+ namespace=ri.ns_name)
+ device_exists = ip_lib.device_exists(rtr_2_fip_name,
+ self.root_helper,
+ namespace=ri.ns_name)
+ if not device_exists:
+ int_dev = ip_wrapper.add_veth(rtr_2_fip_name,
+ fip_2_rtr_name,
+ fip_ns_name)
+ self._internal_ns_interface_added(str(rtr_2_fip),
+ rtr_2_fip_name,
+ ri.ns_name)
+ self._internal_ns_interface_added(str(fip_2_rtr),
+ fip_2_rtr_name,
+ fip_ns_name)
+ int_dev[0].link.set_up()
+ int_dev[1].link.set_up()
+
+ # add default route for the link local interface
+ device = ip_lib.IPDevice(rtr_2_fip_name,
+ self.root_helper,
+ namespace=ri.ns_name)
+ device.route.add_gateway(str(fip_2_rtr.ip), table=FIP_RT_TBL)
+ #setup the NAT rules and chains
+ ri._handle_fip_nat_rules(rtr_2_fip_name, 'add_rules')
+
+ def scan_fip_ports(self, ri):
+ # don't scan if not dvr or count is not None
+ if ri.dist_fip_count is not None:
+ return
+
+ # scan system for any existing fip ports
+ ri.dist_fip_count = 0
+ rtr_2_fip_interface = self.get_rtr_ext_device_name(ri.router_id)
+ if ip_lib.device_exists(rtr_2_fip_interface,
+ root_helper=self.root_helper,
+ namespace=ri.ns_name):
+ device = ip_lib.IPDevice(rtr_2_fip_interface,
+ self.root_helper,
+ namespace=ri.ns_name)
+ existing_cidrs = [addr['cidr'] for addr in device.addr.list()]
+ fip_cidrs = [c for c in existing_cidrs if
+ common_utils.is_cidr_host(c)]
+ ri.dist_fip_count = len(fip_cidrs)
# Linklocal subnet for router and floating IP namespace link
self.rtr_fip_subnet = None
self.dist_fip_count = None
+
+ def _handle_fip_nat_rules(self, interface_name, action):
+ """Configures NAT rules for Floating IPs for DVR.
+
+ Remove all the rules. This is safe because if
+ use_namespaces is set as False then the agent can
+ only configure one router, otherwise each router's
+ NAT rules will be in their own namespace.
+ """
+ self.iptables_manager.ipv4['nat'].empty_chain('POSTROUTING')
+ self.iptables_manager.ipv4['nat'].empty_chain('snat')
+
+ # Add back the jump to float-snat
+ self.iptables_manager.ipv4['nat'].add_rule('snat', '-j $float-snat')
+
+ # And add them back if the action is add_rules
+ if action == 'add_rules' and interface_name:
+ rule = ('POSTROUTING', '! -i %(interface_name)s '
+ '! -o %(interface_name)s -m conntrack ! '
+ '--ctstate DNAT -j ACCEPT' %
+ {'interface_name': interface_name})
+ self.iptables_manager.ipv4['nat'].add_rule(*rule)
+ self.iptables_manager.apply()
self.assertTrue(floating_ips)
external_port = self.agent._get_ex_gw_port(router)
- fip_ns_name = (
- self.agent.get_fip_ns_name(floating_ips[0]['floating_network_id'])
- )
+ fip_ns = self.agent.get_fip_ns(floating_ips[0]['floating_network_id'])
+ fip_ns_name = fip_ns.get_name()
fg_port_created_succesfully = ip_lib.device_exists_with_ip_mac(
- self.agent.get_fip_ext_device_name(external_port['id']),
+ fip_ns.get_ext_device_name(external_port['id']),
external_port['ip_cidr'],
external_port['mac_address'],
fip_ns_name, self.root_helper)
self.assertTrue(fg_port_created_succesfully)
# Check fpr-router device has been created
- device_name = self.agent.get_fip_int_device_name(router.router_id)
+ device_name = fip_ns.get_int_device_name(router.router_id)
fpr_router_device_created_succesfully = ip_lib.device_exists(
device_name, self.root_helper, fip_ns_name)
self.assertTrue(fpr_router_device_created_succesfully)
# In the router namespace
# Check rfp-<router-id> is created correctly
for fip in floating_ips:
- device_name = self.agent.get_rtr_int_device_name(router.router_id)
+ device_name = fip_ns.get_rtr_ext_device_name(router.router_id)
self.assertTrue(ip_lib.device_exists(
device_name, self.root_helper, router.ns_name))
--- /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
+
+from neutron.agent.l3 import dvr_fip_ns
+from neutron.agent.l3 import link_local_allocator as lla
+from neutron.agent.linux import ip_lib
+from neutron.openstack.common import uuidutils
+from neutron.tests import base
+
+_uuid = uuidutils.generate_uuid
+
+
+class TestDvrFipNs(base.BaseTestCase):
+ def setUp(self):
+ super(TestDvrFipNs, self).setUp()
+ self.conf = mock.Mock()
+ self.conf.state_path = '/tmp'
+ self.driver = mock.Mock()
+ self.driver.DEV_NAME_LEN = 14
+ self.net_id = _uuid()
+ self.fip_ns = dvr_fip_ns.FipNamespace(self.net_id,
+ self.conf,
+ self.driver,
+ mock.sentinel.root_helper,
+ use_ipv6=True)
+
+ def test_subscribe(self):
+ is_first = self.fip_ns.subscribe(mock.sentinel.router_id)
+ self.assertTrue(is_first)
+
+ def test_subscribe_not_first(self):
+ self.fip_ns.subscribe(mock.sentinel.router_id)
+ is_first = self.fip_ns.subscribe(mock.sentinel.router_id2)
+ self.assertFalse(is_first)
+
+ def test_unsubscribe(self):
+ self.fip_ns.subscribe(mock.sentinel.router_id)
+ is_last = self.fip_ns.unsubscribe(mock.sentinel.router_id)
+ self.assertTrue(is_last)
+
+ def test_unsubscribe_not_last(self):
+ self.fip_ns.subscribe(mock.sentinel.router_id)
+ self.fip_ns.subscribe(mock.sentinel.router_id2)
+ is_last = self.fip_ns.unsubscribe(mock.sentinel.router_id2)
+ self.assertFalse(is_last)
+
+ def test_allocate_rule_priority(self):
+ pr = self.fip_ns.allocate_rule_priority()
+ self.assertNotIn(pr, self.fip_ns._rule_priorities)
+
+ def test_deallocate_rule_priority(self):
+ pr = self.fip_ns.allocate_rule_priority()
+ self.fip_ns.deallocate_rule_priority(pr)
+ self.assertIn(pr, self.fip_ns._rule_priorities)
+
+ @mock.patch.object(ip_lib, 'IPWrapper')
+ @mock.patch.object(ip_lib, 'IPDevice')
+ @mock.patch.object(ip_lib, 'send_gratuitous_arp')
+ @mock.patch.object(ip_lib, 'device_exists')
+ def test_gateway_added(self, device_exists, send_arp, IPDevice, IPWrapper):
+ 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': self.net_id,
+ 'mac_address': 'ca:fe:de:ad:be:ef',
+ 'ip_cidr': '20.0.0.30/24'}
+
+ device_exists.return_value = False
+ self.fip_ns._gateway_added(agent_gw_port,
+ mock.sentinel.interface_name)
+ self.assertEqual(self.driver.plug.call_count, 1)
+ self.assertEqual(self.driver.init_l3.call_count, 1)
+ send_arp.assert_called_once_with(self.fip_ns.get_name(),
+ mock.sentinel.interface_name,
+ '20.0.0.30',
+ mock.ANY, mock.ANY)
+
+ @mock.patch.object(ip_lib, 'IPWrapper')
+ def test_destroy(self, IPWrapper):
+ ip_wrapper = IPWrapper()
+ dev1 = mock.Mock()
+ dev1.name = 'fpr-aaaa'
+ dev2 = mock.Mock()
+ dev2.name = 'fg-aaaa'
+ ip_wrapper.get_devices.return_value = [dev1, dev2]
+
+ self.fip_ns.destroy()
+
+ ext_net_bridge = self.conf.external_network_bridge
+ ns_name = self.fip_ns.get_name()
+ self.driver.unplug.assert_called_once_with('fg-aaaa',
+ bridge=ext_net_bridge,
+ prefix='fg-',
+ namespace=ns_name)
+ ip_wrapper.del_veth.assert_called_once_with('fpr-aaaa')
+
+ @mock.patch.object(ip_lib, 'IPWrapper')
+ @mock.patch.object(ip_lib, 'IPDevice')
+ @mock.patch.object(ip_lib, 'device_exists')
+ def test_create_rtr_2_fip_link(self, device_exists, IPDevice, IPWrapper):
+ ri = mock.Mock()
+ ri.router_id = _uuid()
+ ri.rtr_fip_subnet = None
+ ri.ns_name = mock.sentinel.router_ns
+
+ rtr_2_fip_name = self.fip_ns.get_rtr_ext_device_name(ri.router_id)
+ fip_2_rtr_name = self.fip_ns.get_int_device_name(ri.router_id)
+ fip_ns_name = self.fip_ns.get_name()
+
+ self.fip_ns.local_subnets = allocator = mock.Mock()
+ pair = lla.LinkLocalAddressPair('169.254.31.28/31')
+ allocator.allocate.return_value = pair
+ device_exists.return_value = False
+ self.fip_ns.create_rtr_2_fip_link(ri)
+
+ ip_wrapper = IPWrapper()
+ ip_wrapper.add_veth.assert_called_with(rtr_2_fip_name,
+ fip_2_rtr_name,
+ fip_ns_name)
+
+ device = IPDevice()
+ device.route.add_gateway.assert_called_once_with(
+ '169.254.31.29', table=16)
+
+ @mock.patch.object(ip_lib, 'IPWrapper')
+ @mock.patch.object(ip_lib, 'IPDevice')
+ @mock.patch.object(ip_lib, 'device_exists')
+ def test_create_rtr_2_fip_link_already_exists(self,
+ device_exists,
+ IPDevice,
+ IPWrapper):
+ ri = mock.Mock()
+ ri.router_id = _uuid()
+ ri.rtr_fip_subnet = None
+ device_exists.return_value = True
+
+ self.fip_ns.local_subnets = allocator = mock.Mock()
+ pair = lla.LinkLocalAddressPair('169.254.31.28/31')
+ allocator.allocate.return_value = pair
+ self.fip_ns.create_rtr_2_fip_link(ri)
+
+ ip_wrapper = IPWrapper()
+ self.assertFalse(ip_wrapper.add_veth.called)
+
+ @mock.patch.object(ip_lib, 'IPDevice')
+ def _test_scan_fip_ports(self, ri, ip_list, IPDevice):
+ IPDevice.return_value = device = mock.Mock()
+ device.addr.list.return_value = ip_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)
+
+ @mock.patch.object(ip_lib, 'device_exists')
+ def test_scan_fip_ports_restart_fips(self, device_exists):
+ device_exists.return_value = True
+ ri = mock.Mock()
+ ri.dist_fip_count = None
+ ip_list = [{'cidr': '111.2.3.4/32'}, {'cidr': '111.2.3.5/32'}]
+ self._test_scan_fip_ports(ri, ip_list)
+ self.assertEqual(2, ri.dist_fip_count)
+
+ @mock.patch.object(ip_lib, 'device_exists')
+ def test_scan_fip_ports_restart_none(self, device_exists):
+ device_exists.return_value = True
+ ri = mock.Mock()
+ ri.dist_fip_count = None
+ 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.assertEqual(0, ri.dist_fip_count)
from neutron.agent.l3 import agent as l3_agent
from neutron.agent.l3 import config as l3_config
from neutron.agent.l3 import dvr
+from neutron.agent.l3 import dvr_fip_ns
from neutron.agent.l3 import dvr_router
from neutron.agent.l3 import ha
from neutron.agent.l3 import link_local_allocator as lla
ri = l3router.RouterInfo(router['id'], router,
ns_name=agent.get_ns_name(router['id']),
**self.ri_kwargs)
+ ex_net_id = _uuid()
# Special setup for dvr routers
if router.get('distributed'):
agent.conf.agent_mode = 'dvr_snat'
agent.host = HOSTNAME
agent._create_dvr_gateway = mock.Mock()
agent.get_snat_interfaces = mock.Mock(return_value=self.snat_ports)
+ ri.fip_ns = agent.get_fip_ns(ex_net_id)
ex_gw_port = {'fixed_ips': [{'ip_address': '20.0.0.30',
'subnet_id': _uuid()}],
'subnet': {'gateway_ip': '20.0.0.1'},
'extra_subnets': [{'cidr': '172.16.0.0/24'}],
'id': _uuid(),
- 'network_id': _uuid(),
+ 'network_id': ex_net_id,
'mac_address': 'ca:fe:de:ad:be:ef',
'ip_cidr': '20.0.0.30/24'}
interface_name = agent.get_external_device_name(ex_gw_port['id'])
4, '1.5.25.15', '00:44:33:22:11:55')
agent.router_deleted(None, router['id'])
- @mock.patch('neutron.agent.linux.ip_lib.IPDevice')
- def _test_scan_fip_ports(self, ri, ip_list, IPDevice):
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
- self.device_exists.return_value = True
- IPDevice.return_value = device = mock.Mock()
- device.addr.list.return_value = ip_list
- agent.scan_fip_ports(ri)
-
- def test_scan_fip_ports_restart_fips(self):
- router = prepare_router_data()
- ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
- ri.router['distributed'] = True
- ip_list = [{'cidr': '111.2.3.4/32'}, {'cidr': '111.2.3.5/32'}]
- self._test_scan_fip_ports(ri, ip_list)
- self.assertEqual(ri.dist_fip_count, 2)
-
- def test_scan_fip_ports_restart_none(self):
- router = prepare_router_data()
- ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
- ri.router['distributed'] = True
- ip_list = []
- self._test_scan_fip_ports(ri, ip_list)
- self.assertEqual(ri.dist_fip_count, 0)
-
- def test_scan_fip_ports_restart_zero(self):
- router = prepare_router_data()
- ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
- ri.router['distributed'] = True
- ri.dist_fip_count = 0
- ip_list = None
- self._test_scan_fip_ports(ri, ip_list)
- self.assertEqual(ri.dist_fip_count, 0)
-
def test_process_cent_router(self):
router = prepare_router_data()
ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
IPDevice.return_value = device = mock.Mock()
device.addr.list.return_value = []
ri.iptables_manager.ipv4['nat'] = mock.MagicMock()
- ex_gw_port = {'id': _uuid()}
+ ex_gw_port = {'id': _uuid(), 'network_id': mock.sentinel.ext_net_id}
with mock.patch.object(lla.LinkLocalAllocator, '_write'):
if ri.router['distributed']:
+ ri.fip_ns = agent.get_fip_ns(ex_gw_port['network_id'])
agent.create_dvr_fip_interfaces(ri, ex_gw_port)
fip_statuses = agent.process_router_floating_ip_addresses(
ri, ex_gw_port)
'host': HOSTNAME,
'floating_ip_address': '15.1.2.3',
'fixed_ip_address': '192.168.0.1',
- 'floating_network_id': _uuid(),
+ 'floating_network_id': mock.sentinel.ext_net_id,
'port_id': _uuid()},
{'id': _uuid(),
'host': 'some-other-host',
'floating_ip_address': '15.1.2.4',
'fixed_ip_address': '192.168.0.10',
- 'floating_network_id': _uuid(),
+ 'floating_network_id': mock.sentinel.ext_net_id,
'port_id': _uuid()}]}
router = prepare_router_data(enable_snat=True)
ri.dist_fip_count = 0
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.host = HOSTNAME
- agent.agent_gateway_port = (
+ fip_ns = agent.get_fip_ns(mock.sentinel.ext_net_id)
+ fip_ns.agent_gateway_port = (
{'fixed_ips': [{'ip_address': '20.0.0.30',
'subnet_id': _uuid()}],
'subnet': {'gateway_ip': '20.0.0.1'},
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
fip_statuses = agent.process_router_floating_ip_addresses(
- ri, {'id': _uuid()})
+ ri, {'id': _uuid(), 'network_id': mock.sentinel.ext_net_id})
self.assertIsNone(fip_statuses.get(fip_id))
agent.router_added_to_agent(None, [FAKE_ID])
self.assertEqual(1, agent._queue.add.call_count)
- def test_destroy_fip_namespace(self):
- namespaces = ['qrouter-foo', 'qrouter-bar']
-
- self.mock_ip.get_namespaces.return_value = namespaces
- self.mock_ip.get_devices.return_value = [FakeDev('fpr-aaaa'),
- FakeDev('fg-aaaa')]
-
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
-
- agent._destroy_fip_namespace(namespaces[0])
- self.mock_driver.unplug.assert_called_once_with('fg-aaaa',
- bridge='br-ex',
- prefix='fg-',
- namespace='qrouter'
- '-foo')
- self.mock_ip.del_veth.assert_called_once_with('fpr-aaaa')
-
def test_destroy_namespace(self):
namespace = 'qrouter-bar'
self.assertEqual(self.mock_driver.plug.call_count, 3)
self.assertEqual(self.mock_driver.init_l3.call_count, 3)
- def test_agent_gateway_added(self):
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
- network_id = _uuid()
- port_id = _uuid()
- agent_gw_port = {'fixed_ips': [{'ip_address': '20.0.0.30',
- 'subnet_id': _uuid()}],
- 'subnet': {'gateway_ip': '20.0.0.1'},
- 'id': port_id,
- 'network_id': network_id,
- 'mac_address': 'ca:fe:de:ad:be:ef',
- 'ip_cidr': '20.0.0.30/24'}
- fip_ns_name = (
- agent.get_fip_ns_name(str(network_id)))
- interface_name = (
- agent.get_fip_ext_device_name(port_id))
-
- self.device_exists.return_value = False
- agent.agent_gateway_added(fip_ns_name, agent_gw_port,
- interface_name)
- self.assertEqual(self.mock_driver.plug.call_count, 1)
- self.assertEqual(self.mock_driver.init_l3.call_count, 1)
- if self.conf.use_namespaces:
- self.send_arp.assert_called_once_with(fip_ns_name, interface_name,
- '20.0.0.30',
- mock.ANY, mock.ANY)
- else:
- self.utils_exec.assert_any_call(
- check_exit_code=True, root_helper=self.conf.root_helper)
-
- def test_create_rtr_2_fip_link(self):
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
- router = prepare_router_data()
- fip = {'id': _uuid(),
- 'host': HOSTNAME,
- 'floating_ip_address': '15.1.2.3',
- 'fixed_ip_address': '192.168.0.1',
- 'floating_network_id': _uuid(),
- 'port_id': _uuid()}
-
- ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
-
- rtr_2_fip_name = agent.get_rtr_int_device_name(ri.router_id)
- fip_2_rtr_name = agent.get_fip_int_device_name(ri.router_id)
- fip_ns_name = agent.get_fip_ns_name(str(fip['floating_network_id']))
-
- with mock.patch.object(lla.LinkLocalAllocator, '_write'):
- self.device_exists.return_value = False
- agent.create_rtr_2_fip_link(ri, fip['floating_network_id'])
- self.mock_ip.add_veth.assert_called_with(rtr_2_fip_name,
- fip_2_rtr_name, fip_ns_name)
- # TODO(mrsmith): add more aasserts -
- self.mock_ip_dev.route.add_gateway.assert_called_once_with(
- '169.254.31.29', table=16)
-
- # TODO(mrsmith): test _create_agent_gateway_port
-
- def test_create_rtr_2_fip_link_already_exists(self):
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
- router = prepare_router_data()
-
- ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
- self.device_exists.return_value = True
- with mock.patch.object(lla.LinkLocalAllocator, '_write'):
- agent.create_rtr_2_fip_link(ri, {})
- self.assertFalse(self.mock_ip.add_veth.called)
-
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': _uuid(),
+ 'network_id': ext_net_id,
'mac_address': 'ca:fe:de:ad:be:ef',
'ip_cidr': '20.0.0.30/24'}
'host': HOSTNAME,
'floating_ip_address': '15.1.2.3',
'fixed_ip_address': '192.168.0.1',
- 'floating_network_id': _uuid(),
+ 'floating_network_id': ext_net_id,
'port_id': _uuid()}
- agent.agent_gateway_port = agent_gw_port
+ 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'])
self.mock_rule.add.assert_called_with('192.168.0.1', 16, FIP_PRI)
# TODO(mrsmith): add more asserts
- @mock.patch.object(l3_agent.L3NATAgent, '_fip_ns_unsubscribe')
@mock.patch.object(lla.LinkLocalAllocator, '_write')
- def test_floating_ip_removed_dist(self, write, unsubscribe):
+ 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',
ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
ri.dist_fip_count = 2
- agent.fip_ns_subscribers.add(ri.router_id)
+ 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'
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(unsubscribe.called, '_fip_ns_unsubscribe called!')
+ 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 = agent.get_fip_ns_name(
- str(agent._fetch_external_net_id()))
- ri.rtr_fip_subnet = agent.local_subnets.allocate(ri.router_id)
+ 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(
- agent.get_fip_int_device_name(router['id']))
+ 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)
- unsubscribe.assert_called_once_with(ri.router_id)
+ 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.assertRaises(messaging.MessagingTimeout, l3_agent.L3NATAgent,
HOSTNAME, self.conf)
- def test__fip_ns_subscribe_is_first_true(self):
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
- router_id = _uuid()
- is_first = agent._fip_ns_subscribe(router_id)
- self.assertTrue(is_first)
- self.assertEqual(len(agent.fip_ns_subscribers), 1)
-
- def test__fip_ns_subscribe_is_first_false(self):
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
- router_id = _uuid()
- router2_id = _uuid()
- agent._fip_ns_subscribe(router_id)
- is_first = agent._fip_ns_subscribe(router2_id)
- self.assertFalse(is_first)
- self.assertEqual(len(agent.fip_ns_subscribers), 2)
-
- def test__fip_ns_unsubscribe_is_last_true(self):
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
- router_id = _uuid()
- agent.fip_ns_subscribers.add(router_id)
- is_last = agent._fip_ns_unsubscribe(router_id)
- self.assertTrue(is_last)
- self.assertEqual(len(agent.fip_ns_subscribers), 0)
-
- def test__fip_ns_unsubscribe_is_last_false(self):
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
- router_id = _uuid()
- router2_id = _uuid()
- agent.fip_ns_subscribers.add(router_id)
- agent.fip_ns_subscribers.add(router2_id)
- is_last = agent._fip_ns_unsubscribe(router_id)
- self.assertFalse(is_last)
- self.assertEqual(len(agent.fip_ns_subscribers), 1)
-
def test_external_gateway_removed_ext_gw_port_and_fip(self):
self.conf.set_override('state_path', '/tmp')
self.conf.set_override('router_delete_namespaces', True)
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
agent.conf.agent_mode = 'dvr'
- agent.agent_gateway_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'}
- external_net_id = _uuid()
- agent._fetch_external_net_id = mock.Mock(return_value=external_net_id)
-
router = prepare_router_data(num_internal_ports=2)
router['distributed'] = True
router['gw_port_host'] = HOSTNAME
+ external_net_id = router['gw_port']['network_id']
ri = dvr_router.DvrRouter(router['id'], router, **self.ri_kwargs)
+ ri.fip_ns = agent.get_fip_ns(external_net_id)
+ ri.fip_ns.agent_gateway_port = {
+ 'fixed_ips': [{'ip_address': '20.0.0.30', 'subnet_id': _uuid()}],
+ 'subnet': {'gateway_ip': '20.0.0.1'},
+ 'id': _uuid(),
+ 'network_id': external_net_id,
+ 'mac_address': 'ca:fe:de:ad:be:ef',
+ 'ip_cidr': '20.0.0.30/24'}
+ agent._fetch_external_net_id = mock.Mock(return_value=external_net_id)
+
vm_floating_ip = '19.4.4.2'
ri.floating_ips_dict[vm_floating_ip] = FIP_PRI
ri.dist_fip_count = 1
ri.ex_gw_port = ri.router['gw_port']
del ri.router['gw_port']
- ri.rtr_fip_subnet = agent.local_subnets.allocate(ri.router_id)
+ ri.rtr_fip_subnet = ri.fip_ns.local_subnets.allocate(ri.router_id)
_, fip_to_rtr = ri.rtr_fip_subnet.get_pair()
nat = ri.iptables_manager.ipv4['nat']
nat.clear_rules_by_tag = mock.Mock()
nat.add_rule = mock.Mock()
self.mock_ip.get_devices.return_value = [
- FakeDev(agent.get_fip_ext_device_name(_uuid()))]
+ FakeDev(ri.fip_ns.get_ext_device_name(_uuid()))]
self.mock_ip_dev.addr.list.return_value = [
{'cidr': vm_floating_ip + '/32'},
{'cidr': '19.4.4.1/24'}]
agent.get_external_device_name(ri.ex_gw_port['id']))
self.mock_ip.del_veth.assert_called_once_with(
- agent.get_fip_int_device_name(ri.router['id']))
+ ri.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_RT_TBL)
+ str(fip_to_rtr.ip), table=dvr_fip_ns.FIP_RT_TBL)
self.assertEqual(ri.dist_fip_count, 0)
- self.assertEqual(len(agent.fip_ns_subscribers), 0)
+ self.assertFalse(ri.fip_ns.has_subscribers())
self.assertEqual(self.mock_driver.unplug.call_count, 1)
- self.assertIsNone(agent.agent_gateway_port)
- self.mock_ip.netns.delete.assert_called_once_with(
- agent.get_fip_ns_name(external_net_id))
+ self.assertIsNone(ri.fip_ns.agent_gateway_port)
+ self.mock_ip.netns.delete.assert_called_once_with(ri.fip_ns.get_name())
self.assertFalse(nat.add_rule.called)
nat.clear_rules_by_tag.assert_called_once_with('floating_ip')