Decompose DVR CSNAT L3 Agent from Compute Node L3 Agent
Currently the same dvr router class is used both by the L3 Agent in the compute nodes that is responsible for the virtual routers namespace and the fip namespace and also used by the centralized SNAT L3 Agent in the network node. This is the first step to decompose the two into different classes. The above means that we have one class of DVR router which is used for two jobs (the virtual router namespace wiring and the fips wiring in the compute node in one hand and the centralized snat wiring in the other) The end goal of this patch is to separate the two into different classes which will also help maintaining it and also help projects that want to use one but not the other (for example only use the centralized SNAT behaviour with there own DVR implementation) Change-Id: I581a097b9e7c49f20d0eb0e4ca66a25e90d9511b Partial-Bug: #1458541 Partially-Implements: blueprint dvr-router-code-decompose
This commit is contained in:
parent
1ab4fc7319
commit
35654ec23e
|
@ -23,7 +23,8 @@ from oslo_utils import importutils
|
|||
from oslo_utils import timeutils
|
||||
|
||||
from neutron.agent.l3 import dvr
|
||||
from neutron.agent.l3 import dvr_router
|
||||
from neutron.agent.l3 import dvr_edge_router as dvr_router
|
||||
from neutron.agent.l3 import dvr_local_router as dvr_local_router
|
||||
from neutron.agent.l3 import ha
|
||||
from neutron.agent.l3 import ha_router
|
||||
from neutron.agent.l3 import legacy_router
|
||||
|
@ -300,7 +301,10 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
|
|||
if router.get('distributed'):
|
||||
kwargs['agent'] = self
|
||||
kwargs['host'] = self.host
|
||||
return dvr_router.DvrRouter(*args, **kwargs)
|
||||
if self.conf.agent_mode == l3_constants.L3_AGENT_MODE_DVR_SNAT:
|
||||
return dvr_router.DvrEdgeRouter(*args, **kwargs)
|
||||
else:
|
||||
return dvr_local_router.DvrLocalRouter(*args, **kwargs)
|
||||
|
||||
if router.get('ha'):
|
||||
kwargs['state_change_callback'] = self.enqueue_state_change
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
# 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.
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from neutron.agent.l3 import dvr_local_router
|
||||
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
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DvrEdgeRouter(dvr_local_router.DvrLocalRouter):
|
||||
|
||||
def __init__(self, agent, host, *args, **kwargs):
|
||||
super(DvrEdgeRouter, self).__init__(agent, host, *args, **kwargs)
|
||||
self.snat_namespace = None
|
||||
|
||||
def external_gateway_added(self, ex_gw_port, interface_name):
|
||||
super(DvrEdgeRouter, self).external_gateway_added(
|
||||
ex_gw_port, interface_name)
|
||||
if self._is_this_snat_host():
|
||||
snat_ports = self.get_snat_interfaces()
|
||||
self._create_dvr_gateway(ex_gw_port, interface_name, snat_ports)
|
||||
|
||||
def external_gateway_updated(self, ex_gw_port, interface_name):
|
||||
if not self._is_this_snat_host():
|
||||
# no centralized SNAT gateway for this node/agent
|
||||
LOG.debug("not hosting snat for router: %s", self.router['id'])
|
||||
return
|
||||
|
||||
self._external_gateway_added(ex_gw_port,
|
||||
interface_name,
|
||||
self.snat_namespace.name,
|
||||
preserve_ips=[])
|
||||
|
||||
def external_gateway_removed(self, ex_gw_port, interface_name):
|
||||
super(DvrEdgeRouter, self).external_gateway_removed(ex_gw_port,
|
||||
interface_name)
|
||||
if not self._is_this_snat_host():
|
||||
# no centralized SNAT gateway for this node/agent
|
||||
LOG.debug("not hosting snat for router: %s", self.router['id'])
|
||||
return
|
||||
|
||||
self.driver.unplug(interface_name,
|
||||
bridge=self.agent_conf.external_network_bridge,
|
||||
namespace=self.snat_namespace.name,
|
||||
prefix=router.EXTERNAL_DEV_PREFIX)
|
||||
self.snat_namespace.delete()
|
||||
self.snat_namespace = None
|
||||
|
||||
def internal_network_added(self, port):
|
||||
super(DvrEdgeRouter, self).internal_network_added(port)
|
||||
|
||||
# TODO(gsagie) some of this checks are already implemented
|
||||
# in the base class, think how to avoid re-doing them
|
||||
if not self._is_this_snat_host():
|
||||
return
|
||||
|
||||
snat_ports = self.get_snat_interfaces()
|
||||
sn_port = self._map_internal_interfaces(port, snat_ports)
|
||||
if not sn_port:
|
||||
return
|
||||
|
||||
ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(self.router['id'])
|
||||
interface_name = self.get_snat_int_device_name(sn_port['id'])
|
||||
self._internal_network_added(
|
||||
ns_name,
|
||||
sn_port['network_id'],
|
||||
sn_port['id'],
|
||||
sn_port['fixed_ips'],
|
||||
sn_port['mac_address'],
|
||||
interface_name,
|
||||
dvr_snat_ns.SNAT_INT_DEV_PREFIX)
|
||||
|
||||
def _dvr_internal_network_removed(self, port):
|
||||
super(DvrEdgeRouter, self)._dvr_internal_network_removed(port)
|
||||
|
||||
if not self.ex_gw_port:
|
||||
return
|
||||
|
||||
sn_port = self._map_internal_interfaces(port, self.snat_ports)
|
||||
if not sn_port:
|
||||
return
|
||||
|
||||
is_this_snat_host = ('binding:host_id' in self.ex_gw_port) and (
|
||||
self.ex_gw_port['binding:host_id'] == self.host)
|
||||
if not is_this_snat_host:
|
||||
return
|
||||
|
||||
snat_interface = self.get_snat_int_device_name(sn_port['id'])
|
||||
ns_name = self.snat_namespace.name
|
||||
prefix = dvr_snat_ns.SNAT_INT_DEV_PREFIX
|
||||
if ip_lib.device_exists(snat_interface, namespace=ns_name):
|
||||
self.driver.unplug(snat_interface, namespace=ns_name,
|
||||
prefix=prefix)
|
||||
|
||||
def _create_dvr_gateway(self, ex_gw_port, gw_interface_name,
|
||||
snat_ports):
|
||||
"""Create SNAT namespace."""
|
||||
snat_ns = self.create_snat_namespace()
|
||||
# connect snat_ports to br_int from SNAT namespace
|
||||
for port in snat_ports:
|
||||
# create interface_name
|
||||
interface_name = self.get_snat_int_device_name(port['id'])
|
||||
self._internal_network_added(
|
||||
snat_ns.name, port['network_id'],
|
||||
port['id'], port['fixed_ips'],
|
||||
port['mac_address'], interface_name,
|
||||
dvr_snat_ns.SNAT_INT_DEV_PREFIX)
|
||||
self._external_gateway_added(ex_gw_port, gw_interface_name,
|
||||
snat_ns.name, preserve_ips=[])
|
||||
self.snat_iptables_manager = iptables_manager.IptablesManager(
|
||||
namespace=snat_ns.name,
|
||||
use_ipv6=self.use_ipv6)
|
||||
# kicks the FW Agent to add rules for the snat namespace
|
||||
self.agent.process_router_add(self)
|
||||
|
||||
def create_snat_namespace(self):
|
||||
# TODO(mlavalle): in the near future, this method should contain the
|
||||
# code in the L3 agent that creates a gateway for a dvr. The first step
|
||||
# is to move the creation of the snat namespace here
|
||||
self.snat_namespace = dvr_snat_ns.SnatNamespace(self.router['id'],
|
||||
self.agent_conf,
|
||||
self.driver,
|
||||
self.use_ipv6)
|
||||
self.snat_namespace.create()
|
||||
return self.snat_namespace
|
||||
|
||||
def get_snat_int_device_name(self, port_id):
|
||||
long_name = dvr_snat_ns.SNAT_INT_DEV_PREFIX + port_id
|
||||
return long_name[:self.driver.DEV_NAME_LEN]
|
||||
|
||||
def _is_this_snat_host(self):
|
||||
return self.get_gw_port_host() == self.host
|
|
@ -19,10 +19,8 @@ from oslo_log import log as logging
|
|||
from oslo_utils import excutils
|
||||
|
||||
from neutron.agent.l3 import dvr_fip_ns
|
||||
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 l3_constants
|
||||
from neutron.common import exceptions
|
||||
from neutron.common import utils as common_utils
|
||||
|
@ -33,9 +31,9 @@ LOG = logging.getLogger(__name__)
|
|||
MASK_30 = 0x3fffffff
|
||||
|
||||
|
||||
class DvrRouter(router.RouterInfo):
|
||||
class DvrLocalRouter(router.RouterInfo):
|
||||
def __init__(self, agent, host, *args, **kwargs):
|
||||
super(DvrRouter, self).__init__(*args, **kwargs)
|
||||
super(DvrLocalRouter, self).__init__(*args, **kwargs)
|
||||
|
||||
self.agent = agent
|
||||
self.host = host
|
||||
|
@ -45,21 +43,16 @@ class DvrRouter(router.RouterInfo):
|
|||
# Linklocal subnet for router and floating IP namespace link
|
||||
self.rtr_fip_subnet = None
|
||||
self.dist_fip_count = None
|
||||
self.snat_namespace = None
|
||||
self.fip_ns = None
|
||||
|
||||
def get_floating_ips(self):
|
||||
"""Filter Floating IPs to be hosted on this agent."""
|
||||
floating_ips = super(DvrRouter, self).get_floating_ips()
|
||||
floating_ips = super(DvrLocalRouter, self).get_floating_ips()
|
||||
return [i for i in floating_ips if i['host'] == self.host]
|
||||
|
||||
def get_snat_interfaces(self):
|
||||
return self.router.get(l3_constants.SNAT_ROUTER_INTF_KEY, [])
|
||||
|
||||
def get_snat_int_device_name(self, port_id):
|
||||
long_name = dvr_snat_ns.SNAT_INT_DEV_PREFIX + port_id
|
||||
return long_name[:self.driver.DEV_NAME_LEN]
|
||||
|
||||
def _handle_fip_nat_rules(self, interface_name, action):
|
||||
"""Configures NAT rules for Floating IPs for DVR.
|
||||
|
||||
|
@ -159,20 +152,9 @@ class DvrRouter(router.RouterInfo):
|
|||
return l3_constants.FLOATINGIP_STATUS_ACTIVE
|
||||
|
||||
def remove_floating_ip(self, device, ip_cidr):
|
||||
super(DvrRouter, self).remove_floating_ip(device, ip_cidr)
|
||||
super(DvrLocalRouter, self).remove_floating_ip(device, ip_cidr)
|
||||
self.floating_ip_removed_dist(ip_cidr)
|
||||
|
||||
def create_snat_namespace(self):
|
||||
# TODO(mlavalle): in the near future, this method should contain the
|
||||
# code in the L3 agent that creates a gateway for a dvr. The first step
|
||||
# is to move the creation of the snat namespace here
|
||||
self.snat_namespace = dvr_snat_ns.SnatNamespace(self.router['id'],
|
||||
self.agent_conf,
|
||||
self.driver,
|
||||
self.use_ipv6)
|
||||
self.snat_namespace.create()
|
||||
return self.snat_namespace
|
||||
|
||||
def _get_internal_port(self, subnet_id):
|
||||
"""Return internal router port based on subnet_id."""
|
||||
router_ports = self.router.get(l3_constants.INTERFACE_KEY, [])
|
||||
|
@ -309,14 +291,8 @@ class DvrRouter(router.RouterInfo):
|
|||
self.router['id'])
|
||||
return host
|
||||
|
||||
def _is_this_snat_host(self):
|
||||
# TODO(Carl) This is a sign that dvr needs two router classes.
|
||||
mode = self.agent_conf.agent_mode
|
||||
return (mode == l3_constants.L3_AGENT_MODE_DVR_SNAT
|
||||
and self.get_gw_port_host() == self.host)
|
||||
|
||||
def internal_network_added(self, port):
|
||||
super(DvrRouter, self).internal_network_added(port)
|
||||
super(DvrLocalRouter, self).internal_network_added(port)
|
||||
|
||||
# NOTE: The following function _set_subnet_arp_info
|
||||
# should be called to dynamically populate the arp
|
||||
|
@ -338,20 +314,6 @@ class DvrRouter(router.RouterInfo):
|
|||
interface_name = self.get_internal_device_name(port['id'])
|
||||
self._snat_redirect_add(sn_port, port, interface_name)
|
||||
|
||||
if not self._is_this_snat_host():
|
||||
return
|
||||
|
||||
ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(self.router['id'])
|
||||
interface_name = self.get_snat_int_device_name(sn_port['id'])
|
||||
self._internal_network_added(
|
||||
ns_name,
|
||||
sn_port['network_id'],
|
||||
sn_port['id'],
|
||||
sn_port['fixed_ips'],
|
||||
sn_port['mac_address'],
|
||||
interface_name,
|
||||
dvr_snat_ns.SNAT_INT_DEV_PREFIX)
|
||||
|
||||
def _dvr_internal_network_removed(self, port):
|
||||
if not self.ex_gw_port:
|
||||
return
|
||||
|
@ -364,23 +326,9 @@ class DvrRouter(router.RouterInfo):
|
|||
interface_name = self.get_internal_device_name(port['id'])
|
||||
self._snat_redirect_remove(sn_port, port, interface_name)
|
||||
|
||||
mode = self.agent_conf.agent_mode
|
||||
is_this_snat_host = (mode == l3_constants.L3_AGENT_MODE_DVR_SNAT
|
||||
and self.ex_gw_port['binding:host_id'] == self.host)
|
||||
if not is_this_snat_host:
|
||||
return
|
||||
|
||||
snat_interface = (
|
||||
self.get_snat_int_device_name(sn_port['id']))
|
||||
ns_name = self.snat_namespace.name
|
||||
prefix = dvr_snat_ns.SNAT_INT_DEV_PREFIX
|
||||
if ip_lib.device_exists(snat_interface, namespace=ns_name):
|
||||
self.driver.unplug(snat_interface, namespace=ns_name,
|
||||
prefix=prefix)
|
||||
|
||||
def internal_network_removed(self, port):
|
||||
self._dvr_internal_network_removed(port)
|
||||
super(DvrRouter, self).internal_network_removed(port)
|
||||
super(DvrLocalRouter, self).internal_network_removed(port)
|
||||
|
||||
def get_floating_agent_gw_interface(self, ext_net_id):
|
||||
"""Filter Floating Agent GW port for the external network."""
|
||||
|
@ -393,26 +341,6 @@ class DvrRouter(router.RouterInfo):
|
|||
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)
|
||||
|
||||
def _create_dvr_gateway(self, ex_gw_port, gw_interface_name,
|
||||
snat_ports):
|
||||
"""Create SNAT namespace."""
|
||||
snat_ns = self.create_snat_namespace()
|
||||
# connect snat_ports to br_int from SNAT namespace
|
||||
for port in snat_ports:
|
||||
# create interface_name
|
||||
interface_name = self.get_snat_int_device_name(port['id'])
|
||||
self._internal_network_added(snat_ns.name, port['network_id'],
|
||||
port['id'], port['fixed_ips'],
|
||||
port['mac_address'], interface_name,
|
||||
dvr_snat_ns.SNAT_INT_DEV_PREFIX)
|
||||
self._external_gateway_added(ex_gw_port, gw_interface_name,
|
||||
snat_ns.name, preserve_ips=[])
|
||||
self.snat_iptables_manager = iptables_manager.IptablesManager(
|
||||
namespace=snat_ns.name,
|
||||
use_ipv6=self.use_ipv6)
|
||||
# kicks the FW Agent to add rules for the snat namespace
|
||||
self.agent.process_router_add(self)
|
||||
|
||||
def external_gateway_added(self, ex_gw_port, interface_name):
|
||||
# TODO(Carl) Refactor external_gateway_added/updated/removed to use
|
||||
# super class implementation where possible. Looks like preserve_ips,
|
||||
|
@ -427,9 +355,6 @@ class DvrRouter(router.RouterInfo):
|
|||
if gateway:
|
||||
self._snat_redirect_add(gateway, p, id_name)
|
||||
|
||||
if self._is_this_snat_host():
|
||||
self._create_dvr_gateway(ex_gw_port, interface_name, snat_ports)
|
||||
|
||||
for port in snat_ports:
|
||||
for ip in port['fixed_ips']:
|
||||
self._update_arp_entry(ip['ip_address'],
|
||||
|
@ -438,15 +363,7 @@ class DvrRouter(router.RouterInfo):
|
|||
'add')
|
||||
|
||||
def external_gateway_updated(self, ex_gw_port, interface_name):
|
||||
if not self._is_this_snat_host():
|
||||
# no centralized SNAT gateway for this node/agent
|
||||
LOG.debug("not hosting snat for router: %s", self.router['id'])
|
||||
return
|
||||
|
||||
self._external_gateway_added(ex_gw_port,
|
||||
interface_name,
|
||||
self.snat_namespace.name,
|
||||
preserve_ips=[])
|
||||
pass
|
||||
|
||||
def external_gateway_removed(self, ex_gw_port, interface_name):
|
||||
# TODO(Carl) Should this be calling process_snat_dnat_for_fip?
|
||||
|
@ -461,19 +378,6 @@ class DvrRouter(router.RouterInfo):
|
|||
internal_interface = self.get_internal_device_name(p['id'])
|
||||
self._snat_redirect_remove(gateway, p, internal_interface)
|
||||
|
||||
if not self._is_this_snat_host():
|
||||
# no centralized SNAT gateway for this node/agent
|
||||
LOG.debug("not hosting snat for router: %s", self.router['id'])
|
||||
return
|
||||
|
||||
self.driver.unplug(interface_name,
|
||||
bridge=self.agent_conf.external_network_bridge,
|
||||
namespace=self.snat_namespace.name,
|
||||
prefix=router.EXTERNAL_DEV_PREFIX)
|
||||
|
||||
self.snat_namespace.delete()
|
||||
self.snat_namespace = None
|
||||
|
||||
def _handle_router_snat_rules(self, ex_gw_port,
|
||||
interface_name, action):
|
||||
if not self.snat_iptables_manager:
|
||||
|
@ -495,13 +399,14 @@ class DvrRouter(router.RouterInfo):
|
|||
if self.get_gw_port_host() != self.host:
|
||||
return
|
||||
|
||||
super(DvrRouter, self).perform_snat_action(snat_callback, *args)
|
||||
super(DvrLocalRouter,
|
||||
self).perform_snat_action(snat_callback, *args)
|
||||
|
||||
def process_external(self, agent):
|
||||
ex_gw_port = self.get_ex_gw_port()
|
||||
if ex_gw_port:
|
||||
self.create_dvr_fip_interfaces(ex_gw_port)
|
||||
super(DvrRouter, self).process_external(agent)
|
||||
super(DvrLocalRouter, self).process_external(agent)
|
||||
|
||||
def create_dvr_fip_interfaces(self, ex_gw_port):
|
||||
floating_ips = self.get_floating_ips()
|
||||
|
@ -532,4 +437,4 @@ class DvrRouter(router.RouterInfo):
|
|||
self.fip_ns = agent.get_fip_ns(ex_gw_port['network_id'])
|
||||
self.fip_ns.scan_fip_ports(self)
|
||||
|
||||
super(DvrRouter, self).process(agent)
|
||||
super(DvrLocalRouter, self).process(agent)
|
|
@ -0,0 +1,268 @@
|
|||
# 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 copy
|
||||
import netaddr
|
||||
from six import moves
|
||||
|
||||
from neutron.common import constants as l3_constants
|
||||
from neutron.openstack.common import uuidutils
|
||||
|
||||
_uuid = uuidutils.generate_uuid
|
||||
|
||||
|
||||
class FakeDev(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
|
||||
def get_ha_interface(ip='169.254.192.1', mac='12:34:56:78:2b:5d'):
|
||||
subnet_id = _uuid()
|
||||
return {'admin_state_up': True,
|
||||
'device_id': _uuid(),
|
||||
'device_owner': 'network:router_ha_interface',
|
||||
'fixed_ips': [{'ip_address': ip,
|
||||
'prefixlen': 18,
|
||||
'subnet_id': subnet_id}],
|
||||
'id': _uuid(),
|
||||
'mac_address': mac,
|
||||
'name': u'L3 HA Admin port 0',
|
||||
'network_id': _uuid(),
|
||||
'status': u'ACTIVE',
|
||||
'subnets': [{'cidr': '169.254.192.0/18',
|
||||
'gateway_ip': '169.254.255.254',
|
||||
'id': subnet_id}],
|
||||
'tenant_id': '',
|
||||
'agent_id': _uuid(),
|
||||
'agent_host': 'aaa',
|
||||
'priority': 1}
|
||||
|
||||
|
||||
def prepare_router_data(ip_version=4, enable_snat=None, num_internal_ports=1,
|
||||
enable_floating_ip=False, enable_ha=False,
|
||||
extra_routes=False, dual_stack=False,
|
||||
v6_ext_gw_with_sub=True, **kwargs):
|
||||
fixed_ips = []
|
||||
subnets = []
|
||||
gateway_mac = kwargs.get('gateway_mac', 'ca:fe:de:ad:be:ee')
|
||||
for loop_version in (4, 6):
|
||||
if loop_version == 4 and (ip_version == 4 or dual_stack):
|
||||
ip_address = kwargs.get('ip_address', '19.4.4.4')
|
||||
prefixlen = 24
|
||||
subnet_cidr = kwargs.get('subnet_cidr', '19.4.4.0/24')
|
||||
gateway_ip = kwargs.get('gateway_ip', '19.4.4.1')
|
||||
elif (loop_version == 6 and (ip_version == 6 or dual_stack) and
|
||||
v6_ext_gw_with_sub):
|
||||
ip_address = kwargs.get('ip_address', 'fd00::4')
|
||||
prefixlen = 64
|
||||
subnet_cidr = kwargs.get('subnet_cidr', 'fd00::/64')
|
||||
gateway_ip = kwargs.get('gateway_ip', 'fd00::1')
|
||||
else:
|
||||
continue
|
||||
subnet_id = _uuid()
|
||||
fixed_ips.append({'ip_address': ip_address,
|
||||
'subnet_id': subnet_id,
|
||||
'prefixlen': prefixlen})
|
||||
subnets.append({'id': subnet_id,
|
||||
'cidr': subnet_cidr,
|
||||
'gateway_ip': gateway_ip})
|
||||
if not fixed_ips and v6_ext_gw_with_sub:
|
||||
raise ValueError("Invalid ip_version: %s" % ip_version)
|
||||
|
||||
router_id = _uuid()
|
||||
ex_gw_port = {'id': _uuid(),
|
||||
'mac_address': gateway_mac,
|
||||
'network_id': _uuid(),
|
||||
'fixed_ips': fixed_ips,
|
||||
'subnets': subnets}
|
||||
|
||||
routes = []
|
||||
if extra_routes:
|
||||
routes = [{'destination': '8.8.8.0/24', 'nexthop': '19.4.4.4'}]
|
||||
|
||||
router = {
|
||||
'id': router_id,
|
||||
'distributed': False,
|
||||
l3_constants.INTERFACE_KEY: [],
|
||||
'routes': routes,
|
||||
'gw_port': ex_gw_port}
|
||||
|
||||
if enable_floating_ip:
|
||||
router[l3_constants.FLOATINGIP_KEY] = [{
|
||||
'id': _uuid(),
|
||||
'port_id': _uuid(),
|
||||
'status': 'DOWN',
|
||||
'floating_ip_address': '19.4.4.2',
|
||||
'fixed_ip_address': '10.0.0.1'}]
|
||||
|
||||
router_append_interface(router, count=num_internal_ports,
|
||||
ip_version=ip_version, dual_stack=dual_stack)
|
||||
if enable_ha:
|
||||
router['ha'] = True
|
||||
router['ha_vr_id'] = 1
|
||||
router[l3_constants.HA_INTERFACE_KEY] = (get_ha_interface())
|
||||
|
||||
if enable_snat is not None:
|
||||
router['enable_snat'] = enable_snat
|
||||
return router
|
||||
|
||||
|
||||
def get_subnet_id(port):
|
||||
return port['fixed_ips'][0]['subnet_id']
|
||||
|
||||
|
||||
def router_append_interface(router, count=1, ip_version=4, ra_mode=None,
|
||||
addr_mode=None, dual_stack=False):
|
||||
interfaces = router[l3_constants.INTERFACE_KEY]
|
||||
current = sum(
|
||||
[netaddr.IPNetwork(subnet['cidr']).version == ip_version
|
||||
for p in interfaces for subnet in p['subnets']])
|
||||
|
||||
mac_address = netaddr.EUI('ca:fe:de:ad:be:ef')
|
||||
mac_address.dialect = netaddr.mac_unix
|
||||
for i in range(current, current + count):
|
||||
fixed_ips = []
|
||||
subnets = []
|
||||
for loop_version in (4, 6):
|
||||
if loop_version == 4 and (ip_version == 4 or dual_stack):
|
||||
ip_pool = '35.4.%i.4'
|
||||
cidr_pool = '35.4.%i.0/24'
|
||||
prefixlen = 24
|
||||
gw_pool = '35.4.%i.1'
|
||||
elif loop_version == 6 and (ip_version == 6 or dual_stack):
|
||||
ip_pool = 'fd01:%x:1::6'
|
||||
cidr_pool = 'fd01:%x:1::/64'
|
||||
prefixlen = 64
|
||||
gw_pool = 'fd01:%x:1::1'
|
||||
else:
|
||||
continue
|
||||
subnet_id = _uuid()
|
||||
fixed_ips.append({'ip_address': ip_pool % i,
|
||||
'subnet_id': subnet_id,
|
||||
'prefixlen': prefixlen})
|
||||
subnets.append({'id': subnet_id,
|
||||
'cidr': cidr_pool % i,
|
||||
'gateway_ip': gw_pool % i,
|
||||
'ipv6_ra_mode': ra_mode,
|
||||
'ipv6_address_mode': addr_mode})
|
||||
if not fixed_ips:
|
||||
raise ValueError("Invalid ip_version: %s" % ip_version)
|
||||
|
||||
interfaces.append(
|
||||
{'id': _uuid(),
|
||||
'network_id': _uuid(),
|
||||
'admin_state_up': True,
|
||||
'fixed_ips': fixed_ips,
|
||||
'mac_address': str(mac_address),
|
||||
'subnets': subnets})
|
||||
mac_address.value += 1
|
||||
|
||||
|
||||
def router_append_subnet(router, count=1, ip_version=4,
|
||||
ipv6_subnet_modes=None, interface_id=None):
|
||||
if ip_version == 6:
|
||||
subnet_mode_none = {'ra_mode': None, 'address_mode': None}
|
||||
if not ipv6_subnet_modes:
|
||||
ipv6_subnet_modes = [subnet_mode_none] * count
|
||||
elif len(ipv6_subnet_modes) != count:
|
||||
ipv6_subnet_modes.extend([subnet_mode_none for i in
|
||||
moves.range(len(ipv6_subnet_modes),
|
||||
count)])
|
||||
|
||||
if ip_version == 4:
|
||||
ip_pool = '35.4.%i.4'
|
||||
cidr_pool = '35.4.%i.0/24'
|
||||
prefixlen = 24
|
||||
gw_pool = '35.4.%i.1'
|
||||
elif ip_version == 6:
|
||||
ip_pool = 'fd01:%x::6'
|
||||
cidr_pool = 'fd01:%x::/64'
|
||||
prefixlen = 64
|
||||
gw_pool = 'fd01:%x::1'
|
||||
else:
|
||||
raise ValueError("Invalid ip_version: %s" % ip_version)
|
||||
|
||||
interfaces = copy.deepcopy(router.get(l3_constants.INTERFACE_KEY, []))
|
||||
if interface_id:
|
||||
try:
|
||||
interface = next(i for i in interfaces
|
||||
if i['id'] == interface_id)
|
||||
except StopIteration:
|
||||
raise ValueError("interface_id not found")
|
||||
|
||||
fixed_ips, subnets = interface['fixed_ips'], interface['subnets']
|
||||
else:
|
||||
interface = None
|
||||
fixed_ips, subnets = [], []
|
||||
|
||||
num_existing_subnets = len(subnets)
|
||||
for i in moves.range(count):
|
||||
subnet_id = _uuid()
|
||||
fixed_ips.append(
|
||||
{'ip_address': ip_pool % (i + num_existing_subnets),
|
||||
'subnet_id': subnet_id,
|
||||
'prefixlen': prefixlen})
|
||||
subnets.append(
|
||||
{'id': subnet_id,
|
||||
'cidr': cidr_pool % (i + num_existing_subnets),
|
||||
'gateway_ip': gw_pool % (i + num_existing_subnets),
|
||||
'ipv6_ra_mode': ipv6_subnet_modes[i]['ra_mode'],
|
||||
'ipv6_address_mode': ipv6_subnet_modes[i]['address_mode']})
|
||||
|
||||
if interface:
|
||||
# Update old interface
|
||||
index = interfaces.index(interface)
|
||||
interfaces[index].update({'fixed_ips': fixed_ips, 'subnets': subnets})
|
||||
else:
|
||||
# New interface appended to interfaces list
|
||||
mac_address = netaddr.EUI('ca:fe:de:ad:be:ef')
|
||||
mac_address.dialect = netaddr.mac_unix
|
||||
interfaces.append(
|
||||
{'id': _uuid(),
|
||||
'network_id': _uuid(),
|
||||
'admin_state_up': True,
|
||||
'mac_address': str(mac_address),
|
||||
'fixed_ips': fixed_ips,
|
||||
'subnets': subnets})
|
||||
|
||||
router[l3_constants.INTERFACE_KEY] = interfaces
|
||||
|
||||
|
||||
def prepare_ext_gw_test(context, ri, dual_stack=False):
|
||||
subnet_id = _uuid()
|
||||
fixed_ips = [{'subnet_id': subnet_id,
|
||||
'ip_address': '20.0.0.30',
|
||||
'prefixlen': 24}]
|
||||
subnets = [{'id': subnet_id,
|
||||
'cidr': '20.0.0.0/24',
|
||||
'gateway_ip': '20.0.0.1'}]
|
||||
if dual_stack:
|
||||
subnet_id_v6 = _uuid()
|
||||
fixed_ips.append({'subnet_id': subnet_id_v6,
|
||||
'ip_address': '2001:192:168:100::2',
|
||||
'prefixlen': 64})
|
||||
subnets.append({'id': subnet_id_v6,
|
||||
'cidr': '2001:192:168:100::/64',
|
||||
'gateway_ip': '2001:192:168:100::1'})
|
||||
ex_gw_port = {'fixed_ips': fixed_ips,
|
||||
'subnets': subnets,
|
||||
'extra_subnets': [{'cidr': '172.16.0.0/24'}],
|
||||
'id': _uuid(),
|
||||
'network_id': _uuid(),
|
||||
'mac_address': 'ca:fe:de:ad:be:ef'}
|
||||
interface_name = ri.get_external_device_name(ex_gw_port['id'])
|
||||
|
||||
context.device_exists.return_value = True
|
||||
|
||||
return interface_name, ex_gw_port
|
|
@ -45,11 +45,12 @@ from neutron.common import config as common_config
|
|||
from neutron.common import constants as l3_constants
|
||||
from neutron.common import utils as common_utils
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.tests.common import l3_test_common
|
||||
from neutron.tests.common import machine_fixtures
|
||||
from neutron.tests.common import net_helpers
|
||||
from neutron.tests.functional.agent.linux import helpers
|
||||
from neutron.tests.functional import base
|
||||
from neutron.tests.unit.agent.l3 import test_agent as test_l3_agent
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
_uuid = uuidutils.generate_uuid
|
||||
|
@ -115,7 +116,7 @@ class L3AgentTestFramework(base.BaseSudoTestCase):
|
|||
enable_fip = False
|
||||
extra_routes = False
|
||||
|
||||
return test_l3_agent.prepare_router_data(ip_version=ip_version,
|
||||
return l3_test_common.prepare_router_data(ip_version=ip_version,
|
||||
enable_snat=enable_snat,
|
||||
enable_floating_ip=enable_fip,
|
||||
enable_ha=enable_ha,
|
||||
|
@ -145,7 +146,7 @@ class L3AgentTestFramework(base.BaseSudoTestCase):
|
|||
ip_version=4,
|
||||
ipv6_subnet_modes=None,
|
||||
interface_id=None):
|
||||
return test_l3_agent.router_append_subnet(router, count,
|
||||
return l3_test_common.router_append_subnet(router, count,
|
||||
ip_version, ipv6_subnet_modes, interface_id)
|
||||
|
||||
def _namespace_exists(self, namespace):
|
||||
|
@ -741,8 +742,8 @@ class L3HATestFramework(L3AgentTestFramework):
|
|||
|
||||
router_info_2 = copy.deepcopy(router_info)
|
||||
router_info_2[l3_constants.HA_INTERFACE_KEY] = (
|
||||
test_l3_agent.get_ha_interface(ip='169.254.192.2',
|
||||
mac='22:22:22:22:22:22'))
|
||||
l3_test_common.get_ha_interface(ip='169.254.192.2',
|
||||
mac='22:22:22:22:22:22'))
|
||||
|
||||
get_ns_name.return_value = "%s%s%s" % (
|
||||
namespaces.RouterNamespace._get_ns_name(router_info_2['id']),
|
||||
|
@ -1038,7 +1039,7 @@ class TestDvrRouter(L3AgentTestFramework):
|
|||
|
||||
def generate_dvr_router_info(
|
||||
self, enable_ha=False, enable_snat=False, **kwargs):
|
||||
router = test_l3_agent.prepare_router_data(
|
||||
router = l3_test_common.prepare_router_data(
|
||||
enable_snat=enable_snat,
|
||||
enable_floating_ip=True,
|
||||
enable_ha=enable_ha,
|
||||
|
@ -1239,7 +1240,7 @@ class TestDvrRouter(L3AgentTestFramework):
|
|||
# existing ports on the the uplinked subnet, the ARP
|
||||
# cache is properly populated.
|
||||
self.agent.conf.agent_mode = 'dvr_snat'
|
||||
router_info = test_l3_agent.prepare_router_data()
|
||||
router_info = l3_test_common.prepare_router_data()
|
||||
router_info['distributed'] = True
|
||||
expected_neighbor = '35.4.1.10'
|
||||
port_data = {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,573 @@
|
|||
# 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 oslo_log import log
|
||||
|
||||
from neutron.agent.common import config as agent_config
|
||||
from neutron.agent.l3 import agent as l3_agent
|
||||
from neutron.agent.l3 import config as l3_config
|
||||
from neutron.agent.l3 import dvr_local_router as dvr_router
|
||||
from neutron.agent.l3 import ha
|
||||
from neutron.agent.l3 import link_local_allocator as lla
|
||||
from neutron.agent.l3 import router_info
|
||||
from neutron.agent.linux import external_process
|
||||
from neutron.agent.linux import interface
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.callbacks import manager
|
||||
from neutron.callbacks import registry
|
||||
from neutron.common import config as base_config
|
||||
from neutron.common import constants as l3_constants
|
||||
from neutron.common import utils as common_utils
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.tests import base
|
||||
from neutron.tests.common import l3_test_common
|
||||
|
||||
_uuid = uuidutils.generate_uuid
|
||||
FIP_PRI = 32768
|
||||
HOSTNAME = 'myhost'
|
||||
|
||||
|
||||
class TestDvrRouterOperations(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDvrRouterOperations, self).setUp()
|
||||
mock.patch('eventlet.spawn').start()
|
||||
self.conf = agent_config.setup_conf()
|
||||
self.conf.register_opts(base_config.core_opts)
|
||||
log.register_options(self.conf)
|
||||
self.conf.register_opts(agent_config.AGENT_STATE_OPTS, 'AGENT')
|
||||
self.conf.register_opts(l3_config.OPTS)
|
||||
self.conf.register_opts(ha.OPTS)
|
||||
agent_config.register_interface_driver_opts_helper(self.conf)
|
||||
agent_config.register_use_namespaces_opts_helper(self.conf)
|
||||
agent_config.register_process_monitor_opts(self.conf)
|
||||
self.conf.register_opts(interface.OPTS)
|
||||
self.conf.register_opts(external_process.OPTS)
|
||||
self.conf.set_override('router_id', 'fake_id')
|
||||
self.conf.set_override('interface_driver',
|
||||
'neutron.agent.linux.interface.NullDriver')
|
||||
self.conf.set_override('send_arp_for_ha', 1)
|
||||
self.conf.set_override('state_path', '')
|
||||
|
||||
self.device_exists_p = mock.patch(
|
||||
'neutron.agent.linux.ip_lib.device_exists')
|
||||
self.device_exists = self.device_exists_p.start()
|
||||
|
||||
self.ensure_dir = mock.patch('neutron.agent.linux.utils'
|
||||
'.ensure_dir').start()
|
||||
|
||||
mock.patch('neutron.agent.linux.keepalived.KeepalivedManager'
|
||||
'.get_full_config_file_path').start()
|
||||
|
||||
self.utils_exec_p = mock.patch(
|
||||
'neutron.agent.linux.utils.execute')
|
||||
self.utils_exec = self.utils_exec_p.start()
|
||||
|
||||
self.utils_replace_file_p = mock.patch(
|
||||
'neutron.agent.linux.utils.replace_file')
|
||||
self.utils_replace_file = self.utils_replace_file_p.start()
|
||||
|
||||
self.external_process_p = mock.patch(
|
||||
'neutron.agent.linux.external_process.ProcessManager')
|
||||
self.external_process = self.external_process_p.start()
|
||||
self.process_monitor = mock.patch(
|
||||
'neutron.agent.linux.external_process.ProcessMonitor').start()
|
||||
|
||||
self.send_adv_notif_p = mock.patch(
|
||||
'neutron.agent.linux.ip_lib.send_ip_addr_adv_notif')
|
||||
self.send_adv_notif = self.send_adv_notif_p.start()
|
||||
|
||||
self.dvr_cls_p = mock.patch('neutron.agent.linux.interface.NullDriver')
|
||||
driver_cls = self.dvr_cls_p.start()
|
||||
self.mock_driver = mock.MagicMock()
|
||||
self.mock_driver.DEV_NAME_LEN = (
|
||||
interface.LinuxInterfaceDriver.DEV_NAME_LEN)
|
||||
driver_cls.return_value = self.mock_driver
|
||||
|
||||
self.ip_cls_p = mock.patch('neutron.agent.linux.ip_lib.IPWrapper')
|
||||
ip_cls = self.ip_cls_p.start()
|
||||
self.mock_ip = mock.MagicMock()
|
||||
ip_cls.return_value = self.mock_ip
|
||||
|
||||
ip_rule = mock.patch('neutron.agent.linux.ip_lib.IPRule').start()
|
||||
self.mock_rule = mock.MagicMock()
|
||||
ip_rule.return_value = self.mock_rule
|
||||
|
||||
ip_dev = mock.patch('neutron.agent.linux.ip_lib.IPDevice').start()
|
||||
self.mock_ip_dev = mock.MagicMock()
|
||||
ip_dev.return_value = self.mock_ip_dev
|
||||
|
||||
self.l3pluginApi_cls_p = mock.patch(
|
||||
'neutron.agent.l3.agent.L3PluginApi')
|
||||
l3pluginApi_cls = self.l3pluginApi_cls_p.start()
|
||||
self.plugin_api = mock.MagicMock()
|
||||
l3pluginApi_cls.return_value = self.plugin_api
|
||||
|
||||
self.looping_call_p = mock.patch(
|
||||
'neutron.openstack.common.loopingcall.FixedIntervalLoopingCall')
|
||||
self.looping_call_p.start()
|
||||
|
||||
subnet_id_1 = _uuid()
|
||||
subnet_id_2 = _uuid()
|
||||
self.snat_ports = [{'subnets': [{'cidr': '152.2.0.0/16',
|
||||
'gateway_ip': '152.2.0.1',
|
||||
'id': subnet_id_1}],
|
||||
'network_id': _uuid(),
|
||||
'device_owner': 'network:router_centralized_snat',
|
||||
'mac_address': 'fa:16:3e:80:8d:80',
|
||||
'fixed_ips': [{'subnet_id': subnet_id_1,
|
||||
'ip_address': '152.2.0.13',
|
||||
'prefixlen': 16}],
|
||||
'id': _uuid(), 'device_id': _uuid()},
|
||||
{'subnets': [{'cidr': '152.10.0.0/16',
|
||||
'gateway_ip': '152.10.0.1',
|
||||
'id': subnet_id_2}],
|
||||
'network_id': _uuid(),
|
||||
'device_owner': 'network:router_centralized_snat',
|
||||
'mac_address': 'fa:16:3e:80:8d:80',
|
||||
'fixed_ips': [{'subnet_id': subnet_id_2,
|
||||
'ip_address': '152.10.0.13',
|
||||
'prefixlen': 16}],
|
||||
'id': _uuid(), 'device_id': _uuid()}]
|
||||
|
||||
self.ri_kwargs = {'agent_conf': self.conf,
|
||||
'interface_driver': self.mock_driver}
|
||||
|
||||
self._callback_manager = manager.CallbacksManager()
|
||||
mock.patch.object(registry, '_get_callback_manager',
|
||||
return_value=self._callback_manager).start()
|
||||
|
||||
def _create_router(self, router=None, **kwargs):
|
||||
agent_conf = mock.Mock()
|
||||
self.router_id = _uuid()
|
||||
if not router:
|
||||
router = mock.MagicMock()
|
||||
return dvr_router.DvrLocalRouter(mock.sentinel.agent,
|
||||
mock.sentinel.myhost,
|
||||
self.router_id,
|
||||
router,
|
||||
agent_conf,
|
||||
mock.sentinel.interface_driver,
|
||||
**kwargs)
|
||||
|
||||
def test_get_floating_ips_dvr(self):
|
||||
router = mock.MagicMock()
|
||||
router.get.return_value = [{'host': mock.sentinel.myhost},
|
||||
{'host': mock.sentinel.otherhost}]
|
||||
ri = self._create_router(router)
|
||||
|
||||
fips = ri.get_floating_ips()
|
||||
|
||||
self.assertEqual([{'host': mock.sentinel.myhost}], fips)
|
||||
|
||||
@mock.patch.object(ip_lib, 'send_ip_addr_adv_notif')
|
||||
@mock.patch.object(ip_lib, 'IPDevice')
|
||||
@mock.patch.object(ip_lib, 'IPRule')
|
||||
def test_floating_ip_added_dist(self, mIPRule, mIPDevice, mock_adv_notif):
|
||||
router = mock.MagicMock()
|
||||
ri = self._create_router(router)
|
||||
ext_net_id = _uuid()
|
||||
subnet_id = _uuid()
|
||||
agent_gw_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': ext_net_id,
|
||||
'mac_address': 'ca:fe:de:ad:be:ef'}
|
||||
|
||||
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().rule.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)
|
||||
|
||||
subnet_id = _uuid()
|
||||
agent_gw_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': _uuid(),
|
||||
'mac_address': 'ca:fe:de:ad:be:ef'}
|
||||
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().rule.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()
|
||||
fip_ns = ri.fip_ns
|
||||
|
||||
ri.floating_ip_removed_dist(fip_cidr)
|
||||
|
||||
self.assertTrue(fip_ns.destroyed)
|
||||
mIPWrapper().del_veth.assert_called_once_with(
|
||||
fip_ns.get_int_device_name(router['id']))
|
||||
mIPDevice().route.delete_gateway.assert_called_once_with(
|
||||
str(fip_to_rtr.ip), table=16)
|
||||
fip_ns.unsubscribe.assert_called_once_with(ri.router_id)
|
||||
|
||||
def _test_add_floating_ip(self, ri, fip, is_failure):
|
||||
ri._add_fip_addr_to_device = mock.Mock(return_value=is_failure)
|
||||
ri.floating_ip_added_dist = mock.Mock()
|
||||
|
||||
result = ri.add_floating_ip(fip,
|
||||
mock.sentinel.interface_name,
|
||||
mock.sentinel.device)
|
||||
ri._add_fip_addr_to_device.assert_called_once_with(
|
||||
fip, mock.sentinel.device)
|
||||
return result
|
||||
|
||||
def test_add_floating_ip(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(l3_constants.FLOATINGIP_STATUS_ACTIVE, result)
|
||||
|
||||
def test_add_floating_ip_error(self):
|
||||
ri = self._create_router(mock.MagicMock())
|
||||
result = self._test_add_floating_ip(
|
||||
ri, {'floating_ip_address': '15.1.2.3'}, False)
|
||||
self.assertFalse(ri.floating_ip_added_dist.called)
|
||||
self.assertEqual(l3_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())
|
||||
ri.floating_ip_removed_dist = mock.Mock()
|
||||
|
||||
ri.remove_floating_ip(mock.sentinel.device, mock.sentinel.ip_cidr)
|
||||
|
||||
super_remove_floating_ip.assert_called_once_with(
|
||||
mock.sentinel.device, mock.sentinel.ip_cidr)
|
||||
ri.floating_ip_removed_dist.assert_called_once_with(
|
||||
mock.sentinel.ip_cidr)
|
||||
|
||||
def test__get_internal_port(self):
|
||||
ri = self._create_router()
|
||||
port = {'fixed_ips': [{'subnet_id': mock.sentinel.subnet_id}]}
|
||||
router_ports = [port]
|
||||
ri.router.get.return_value = router_ports
|
||||
self.assertEqual(port, ri._get_internal_port(mock.sentinel.subnet_id))
|
||||
|
||||
def test__get_internal_port_not_found(self):
|
||||
ri = self._create_router()
|
||||
port = {'fixed_ips': [{'subnet_id': mock.sentinel.subnet_id}]}
|
||||
router_ports = [port]
|
||||
ri.router.get.return_value = router_ports
|
||||
self.assertEqual(None, ri._get_internal_port(mock.sentinel.subnet_id2))
|
||||
|
||||
def test__get_snat_idx_ipv4(self):
|
||||
ip_cidr = '101.12.13.00/24'
|
||||
ri = self._create_router(mock.MagicMock())
|
||||
snat_idx = ri._get_snat_idx(ip_cidr)
|
||||
# 0x650C0D00 is numerical value of 101.12.13.00
|
||||
self.assertEqual(0x650C0D00, snat_idx)
|
||||
|
||||
def test__get_snat_idx_ipv6(self):
|
||||
ip_cidr = '2620:0:a03:e100::/64'
|
||||
ri = self._create_router(mock.MagicMock())
|
||||
snat_idx = ri._get_snat_idx(ip_cidr)
|
||||
# 0x3D345705 is 30 bit xor folded crc32 of the ip_cidr
|
||||
self.assertEqual(0x3D345705, snat_idx)
|
||||
|
||||
def test__get_snat_idx_ipv6_below_32768(self):
|
||||
ip_cidr = 'd488::/30'
|
||||
# crc32 of this ip_cidr is 0x1BD7
|
||||
ri = self._create_router(mock.MagicMock())
|
||||
snat_idx = ri._get_snat_idx(ip_cidr)
|
||||
# 0x1BD7 + 0x3FFFFFFF = 0x40001BD6
|
||||
self.assertEqual(0x40001BD6, snat_idx)
|
||||
|
||||
def test__set_subnet_arp_info(self):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
router = l3_test_common.prepare_router_data(num_internal_ports=2)
|
||||
router['distributed'] = True
|
||||
ri = dvr_router.DvrLocalRouter(
|
||||
agent, HOSTNAME, router['id'], router, **self.ri_kwargs)
|
||||
ports = ri.router.get(l3_constants.INTERFACE_KEY, [])
|
||||
subnet_id = l3_test_common.get_subnet_id(ports[0])
|
||||
test_ports = [{'mac_address': '00:11:22:33:44:55',
|
||||
'device_owner': 'network:dhcp',
|
||||
'fixed_ips': [{'ip_address': '1.2.3.4',
|
||||
'prefixlen': 24,
|
||||
'subnet_id': subnet_id}]}]
|
||||
|
||||
self.plugin_api.get_ports_by_subnet.return_value = test_ports
|
||||
|
||||
# Test basic case
|
||||
ports[0]['subnets'] = [{'id': subnet_id,
|
||||
'cidr': '1.2.3.0/24'}]
|
||||
ri._set_subnet_arp_info(subnet_id)
|
||||
self.mock_ip_dev.neigh.add.assert_called_once_with(
|
||||
'1.2.3.4', '00:11:22:33:44:55')
|
||||
|
||||
# Test negative case
|
||||
router['distributed'] = False
|
||||
ri._set_subnet_arp_info(subnet_id)
|
||||
self.mock_ip_dev.neigh.add.never_called()
|
||||
|
||||
def test_add_arp_entry(self):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
router = l3_test_common.prepare_router_data(num_internal_ports=2)
|
||||
router['distributed'] = True
|
||||
subnet_id = l3_test_common.get_subnet_id(
|
||||
router[l3_constants.INTERFACE_KEY][0])
|
||||
arp_table = {'ip_address': '1.7.23.11',
|
||||
'mac_address': '00:11:22:33:44:55',
|
||||
'subnet_id': subnet_id}
|
||||
|
||||
payload = {'arp_table': arp_table, 'router_id': router['id']}
|
||||
agent._router_added(router['id'], router)
|
||||
agent.add_arp_entry(None, payload)
|
||||
agent.router_deleted(None, router['id'])
|
||||
self.mock_ip_dev.neigh.add.assert_called_once_with(
|
||||
'1.7.23.11', '00:11:22:33:44:55')
|
||||
|
||||
def test_add_arp_entry_no_routerinfo(self):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
router = l3_test_common.prepare_router_data(num_internal_ports=2)
|
||||
subnet_id = l3_test_common.get_subnet_id(
|
||||
router[l3_constants.INTERFACE_KEY][0])
|
||||
arp_table = {'ip_address': '1.7.23.11',
|
||||
'mac_address': '00:11:22:33:44:55',
|
||||
'subnet_id': subnet_id}
|
||||
|
||||
payload = {'arp_table': arp_table, 'router_id': router['id']}
|
||||
agent.add_arp_entry(None, payload)
|
||||
|
||||
def test__update_arp_entry_with_no_subnet(self):
|
||||
ri = dvr_router.DvrLocalRouter(
|
||||
mock.sentinel.agent,
|
||||
HOSTNAME,
|
||||
'foo_router_id',
|
||||
{'distributed': True, 'gw_port_host': HOSTNAME},
|
||||
**self.ri_kwargs)
|
||||
with mock.patch.object(l3_agent.ip_lib, 'IPDevice') as f:
|
||||
ri._update_arp_entry(mock.ANY, mock.ANY, 'foo_subnet_id', 'add')
|
||||
self.assertFalse(f.call_count)
|
||||
|
||||
def test_del_arp_entry(self):
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
router = l3_test_common.prepare_router_data(num_internal_ports=2)
|
||||
router['distributed'] = True
|
||||
subnet_id = l3_test_common.get_subnet_id(
|
||||
router[l3_constants.INTERFACE_KEY][0])
|
||||
arp_table = {'ip_address': '1.5.25.15',
|
||||
'mac_address': '00:44:33:22:11:55',
|
||||
'subnet_id': subnet_id}
|
||||
|
||||
payload = {'arp_table': arp_table, 'router_id': router['id']}
|
||||
agent._router_added(router['id'], router)
|
||||
# first add the entry
|
||||
agent.add_arp_entry(None, payload)
|
||||
# now delete it
|
||||
agent.del_arp_entry(None, payload)
|
||||
self.mock_ip_dev.neigh.delete.assert_called_once_with(
|
||||
'1.5.25.15', '00:44:33:22:11:55')
|
||||
agent.router_deleted(None, router['id'])
|
||||
|
||||
def test_get_floating_agent_gw_interfaces(self):
|
||||
fake_network_id = _uuid()
|
||||
subnet_id = _uuid()
|
||||
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(),
|
||||
'binding:host_id': 'myhost',
|
||||
'device_owner': 'network:floatingip_agent_gateway',
|
||||
'network_id': fake_network_id,
|
||||
'mac_address': 'ca:fe:de:ad:be:ef'}]
|
||||
)
|
||||
|
||||
router = l3_test_common.prepare_router_data(enable_snat=True)
|
||||
router[l3_constants.FLOATINGIP_AGENT_INTF_KEY] = agent_gateway_port
|
||||
router['distributed'] = True
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
ri = dvr_router.DvrLocalRouter(
|
||||
agent, HOSTNAME, router['id'], router, **self.ri_kwargs)
|
||||
self.assertEqual(
|
||||
agent_gateway_port[0],
|
||||
ri.get_floating_agent_gw_interface(fake_network_id))
|
||||
|
||||
def test_process_router_dist_floating_ip_add(self):
|
||||
fake_floatingips = {'floatingips': [
|
||||
{'id': _uuid(),
|
||||
'host': HOSTNAME,
|
||||
'floating_ip_address': '15.1.2.3',
|
||||
'fixed_ip_address': '192.168.0.1',
|
||||
'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': mock.sentinel.ext_net_id,
|
||||
'port_id': _uuid()}]}
|
||||
|
||||
router = l3_test_common.prepare_router_data(enable_snat=True)
|
||||
router[l3_constants.FLOATINGIP_KEY] = fake_floatingips['floatingips']
|
||||
router['distributed'] = True
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
ri = dvr_router.DvrLocalRouter(agent,
|
||||
HOSTNAME,
|
||||
router['id'],
|
||||
router,
|
||||
**self.ri_kwargs)
|
||||
ri.iptables_manager.ipv4['nat'] = mock.MagicMock()
|
||||
ri.dist_fip_count = 0
|
||||
fip_ns = agent.get_fip_ns(mock.sentinel.ext_net_id)
|
||||
subnet_id = _uuid()
|
||||
fip_ns.agent_gateway_port = (
|
||||
{'fixed_ips': [{'ip_address': '20.0.0.30',
|
||||
'subnet_id': subnet_id}],
|
||||
'subnets': [{'id': subnet_id,
|
||||
'cidr': '20.0.0.0/24',
|
||||
'gateway_ip': '20.0.0.1'}],
|
||||
'id': _uuid(),
|
||||
'network_id': _uuid(),
|
||||
'mac_address': 'ca:fe:de:ad:be:ef'}
|
||||
)
|
||||
|
||||
def _test_ext_gw_updated_dvr_agent_mode(self, host,
|
||||
agent_mode, expected_call_count):
|
||||
router = l3_test_common.prepare_router_data(num_internal_ports=2)
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
ri = dvr_router.DvrLocalRouter(agent,
|
||||
HOSTNAME,
|
||||
router['id'],
|
||||
router,
|
||||
**self.ri_kwargs)
|
||||
|
||||
interface_name, ex_gw_port = l3_test_common.prepare_ext_gw_test(self,
|
||||
ri)
|
||||
ri._external_gateway_added = mock.Mock()
|
||||
|
||||
# test agent mode = dvr (compute node)
|
||||
router['gw_port_host'] = host
|
||||
agent.conf.agent_mode = agent_mode
|
||||
|
||||
ri.external_gateway_updated(ex_gw_port, interface_name)
|
||||
# no gateway should be added on dvr node
|
||||
self.assertEqual(expected_call_count,
|
||||
ri._external_gateway_added.call_count)
|
||||
|
||||
def test_ext_gw_updated_dvr_agent_mode(self):
|
||||
# no gateway should be added on dvr node
|
||||
self._test_ext_gw_updated_dvr_agent_mode('any-foo', 'dvr', 0)
|
||||
|
||||
def test_ext_gw_updated_dvr_agent_mode_host(self):
|
||||
# no gateway should be added on dvr node
|
||||
self._test_ext_gw_updated_dvr_agent_mode(HOSTNAME,
|
||||
'dvr', 0)
|
||||
|
||||
def test_external_gateway_removed_ext_gw_port_and_fip(self):
|
||||
self.conf.set_override('state_path', '/tmp')
|
||||
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
agent.conf.agent_mode = 'dvr'
|
||||
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']
|
||||
ri = dvr_router.DvrLocalRouter(
|
||||
agent, HOSTNAME, router['id'], router, **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']
|
||||
del ri.router['gw_port']
|
||||
ri.fip_ns = None
|
||||
nat = ri.iptables_manager.ipv4['nat']
|
||||
nat.clear_rules_by_tag = mock.Mock()
|
||||
nat.add_rule = mock.Mock()
|
||||
|
||||
ri.fip_ns = agent.get_fip_ns(external_net_id)
|
||||
subnet_id = _uuid()
|
||||
ri.fip_ns.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': external_net_id,
|
||||
'mac_address': 'ca:fe:de:ad:be:ef'}
|
||||
|
||||
vm_floating_ip = '19.4.4.2'
|
||||
ri.floating_ips_dict[vm_floating_ip] = FIP_PRI
|
||||
ri.dist_fip_count = 1
|
||||
ri.rtr_fip_subnet = ri.fip_ns.local_subnets.allocate(ri.router_id)
|
||||
_, fip_to_rtr = ri.rtr_fip_subnet.get_pair()
|
||||
self.mock_ip.get_devices.return_value = [
|
||||
l3_test_common.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'}]
|
||||
self.device_exists.return_value = True
|
||||
|
||||
ri.external_gateway_removed(
|
||||
ri.ex_gw_port,
|
||||
ri.get_external_device_name(ri.ex_gw_port['id']))
|
||||
|
||||
ri.remove_floating_ip.assert_called_once_with(self.mock_ip_dev,
|
||||
'19.4.4.2/32')
|
|
@ -1,214 +0,0 @@
|
|||
# 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.l3 import router_info
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.common import constants as l3_constants
|
||||
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=None, **kwargs):
|
||||
agent_conf = mock.Mock()
|
||||
self.router_id = _uuid()
|
||||
if not router:
|
||||
router = mock.MagicMock()
|
||||
return dvr_router.DvrRouter(mock.sentinel.agent,
|
||||
mock.sentinel.myhost,
|
||||
self.router_id,
|
||||
router,
|
||||
agent_conf,
|
||||
mock.sentinel.interface_driver,
|
||||
**kwargs)
|
||||
|
||||
def test_get_floating_ips_dvr(self):
|
||||
router = mock.MagicMock()
|
||||
router.get.return_value = [{'host': mock.sentinel.myhost},
|
||||
{'host': mock.sentinel.otherhost}]
|
||||
ri = self._create_router(router)
|
||||
|
||||
fips = ri.get_floating_ips()
|
||||
|
||||
self.assertEqual([{'host': mock.sentinel.myhost}], fips)
|
||||
|
||||
@mock.patch.object(ip_lib, 'send_ip_addr_adv_notif')
|
||||
@mock.patch.object(ip_lib, 'IPDevice')
|
||||
@mock.patch.object(ip_lib, 'IPRule')
|
||||
def test_floating_ip_added_dist(self, mIPRule, mIPDevice, mock_adv_notif):
|
||||
router = mock.MagicMock()
|
||||
ri = self._create_router(router)
|
||||
ext_net_id = _uuid()
|
||||
subnet_id = _uuid()
|
||||
agent_gw_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': ext_net_id,
|
||||
'mac_address': 'ca:fe:de:ad:be:ef'}
|
||||
|
||||
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().rule.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)
|
||||
|
||||
subnet_id = _uuid()
|
||||
agent_gw_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': _uuid(),
|
||||
'mac_address': 'ca:fe:de:ad:be:ef'}
|
||||
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().rule.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()
|
||||
fip_ns = ri.fip_ns
|
||||
|
||||
ri.floating_ip_removed_dist(fip_cidr)
|
||||
|
||||
self.assertTrue(fip_ns.destroyed)
|
||||
mIPWrapper().del_veth.assert_called_once_with(
|
||||
fip_ns.get_int_device_name(router['id']))
|
||||
mIPDevice().route.delete_gateway.assert_called_once_with(
|
||||
str(fip_to_rtr.ip), table=16)
|
||||
fip_ns.unsubscribe.assert_called_once_with(ri.router_id)
|
||||
|
||||
def _test_add_floating_ip(self, ri, fip, is_failure):
|
||||
ri._add_fip_addr_to_device = mock.Mock(return_value=is_failure)
|
||||
ri.floating_ip_added_dist = mock.Mock()
|
||||
|
||||
result = ri.add_floating_ip(fip,
|
||||
mock.sentinel.interface_name,
|
||||
mock.sentinel.device)
|
||||
ri._add_fip_addr_to_device.assert_called_once_with(
|
||||
fip, mock.sentinel.device)
|
||||
return result
|
||||
|
||||
def test_add_floating_ip(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(l3_constants.FLOATINGIP_STATUS_ACTIVE, result)
|
||||
|
||||
def test_add_floating_ip_error(self):
|
||||
ri = self._create_router(mock.MagicMock())
|
||||
result = self._test_add_floating_ip(
|
||||
ri, {'floating_ip_address': '15.1.2.3'}, False)
|
||||
self.assertFalse(ri.floating_ip_added_dist.called)
|
||||
self.assertEqual(l3_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())
|
||||
ri.floating_ip_removed_dist = mock.Mock()
|
||||
|
||||
ri.remove_floating_ip(mock.sentinel.device, mock.sentinel.ip_cidr)
|
||||
|
||||
super_remove_floating_ip.assert_called_once_with(
|
||||
mock.sentinel.device, mock.sentinel.ip_cidr)
|
||||
ri.floating_ip_removed_dist.assert_called_once_with(
|
||||
mock.sentinel.ip_cidr)
|
||||
|
||||
def test__get_internal_port(self):
|
||||
ri = self._create_router()
|
||||
port = {'fixed_ips': [{'subnet_id': mock.sentinel.subnet_id}]}
|
||||
router_ports = [port]
|
||||
ri.router.get.return_value = router_ports
|
||||
self.assertEqual(port, ri._get_internal_port(mock.sentinel.subnet_id))
|
||||
|
||||
def test__get_internal_port_not_found(self):
|
||||
ri = self._create_router()
|
||||
port = {'fixed_ips': [{'subnet_id': mock.sentinel.subnet_id}]}
|
||||
router_ports = [port]
|
||||
ri.router.get.return_value = router_ports
|
||||
self.assertEqual(None, ri._get_internal_port(mock.sentinel.subnet_id2))
|
||||
|
||||
def test__get_snat_idx_ipv4(self):
|
||||
ip_cidr = '101.12.13.00/24'
|
||||
ri = self._create_router(mock.MagicMock())
|
||||
snat_idx = ri._get_snat_idx(ip_cidr)
|
||||
# 0x650C0D00 is numerical value of 101.12.13.00
|
||||
self.assertEqual(0x650C0D00, snat_idx)
|
||||
|
||||
def test__get_snat_idx_ipv6(self):
|
||||
ip_cidr = '2620:0:a03:e100::/64'
|
||||
ri = self._create_router(mock.MagicMock())
|
||||
snat_idx = ri._get_snat_idx(ip_cidr)
|
||||
# 0x3D345705 is 30 bit xor folded crc32 of the ip_cidr
|
||||
self.assertEqual(0x3D345705, snat_idx)
|
||||
|
||||
def test__get_snat_idx_ipv6_below_32768(self):
|
||||
ip_cidr = 'd488::/30'
|
||||
# crc32 of this ip_cidr is 0x1BD7
|
||||
ri = self._create_router(mock.MagicMock())
|
||||
snat_idx = ri._get_snat_idx(ip_cidr)
|
||||
# 0x1BD7 + 0x3FFFFFFF = 0x40001BD6
|
||||
self.assertEqual(0x40001BD6, snat_idx)
|
Loading…
Reference in New Issue