Merge "OFAgent: Share codes of l2-population in OVS agent"

This commit is contained in:
Jenkins 2014-07-24 09:59:32 +00:00 committed by Gerrit Code Review
commit 75735e9cf1
8 changed files with 843 additions and 257 deletions

View File

@ -22,11 +22,22 @@ import abc
from oslo.config import cfg
import six
from neutron.common import constants as n_const
from neutron.common import log
from neutron.openstack.common import log as logging
LOG = logging.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta)
class L2populationRpcCallBackMixin(object):
'''General mixin class of L2-population RPC call back.
The following methods are called through RPC.
add_fdb_entries(), remove_fdb_entries(), update_fdb_entries()
The following methods are used in a agent as an internal method.
fdb_add(), fdb_remove(), fdb_update()
'''
@log.log
def add_fdb_entries(self, context, fdb_entries, host=None):
@ -54,3 +65,118 @@ class L2populationRpcCallBackMixin(object):
@abc.abstractmethod
def fdb_update(self, context, fdb_entries):
pass
class L2populationRpcCallBackTunnelMixin(L2populationRpcCallBackMixin):
'''Mixin class of L2-population call back for Tunnel.
The following all methods are used in a agent as an internal method.
'''
@abc.abstractmethod
def add_fdb_flow(self, port_info, remote_ip, lvm, ofport):
'''Add flow for fdb
This method assumes to be used by method fdb_add_tun.
We expect to add a flow entry to send a packet to specified port
on bridge.
And you may edit some information for local arp respond.
:param port_info: list to include mac and ip.
[mac, ip]
:remote_ip: remote ip address.
:param lvm: a local VLAN map of network.
:param ofport: a port to add.
'''
pass
@abc.abstractmethod
def del_fdb_flow(self, port_info, remote_ip, lvm, ofport):
'''Delete flow for fdb
This method assumes to be used by method fdb_remove_tun.
We expect to delete a flow entry to send a packet to specified port
from bridge.
And you may delete some information for local arp respond.
:param port_info: a list to contain mac and ip.
[mac, ip]
:remote_ip: remote ip address.
:param lvm: local VLAN map of network.
:param ofport: a port to delete.
'''
pass
@abc.abstractmethod
def setup_tunnel_port(self, remote_ip, network_type):
'''Setup an added tunnel port.
This method assumes to be used by method fdb_add_tun.
We expect to prepare to call add_fdb_flow. It will be mainly adding
a port to a bridge.
If you need, you may do some preparation for a bridge.
:param remote_ip: an ip for port to setup.
:param network_type: a type of network.
:returns: a ofport value. the value 0 means to be unavailable port.
'''
pass
@abc.abstractmethod
def cleanup_tunnel_port(self, tun_ofport, tunnel_type):
'''Clean up a deleted tunnel port.
This method assumes to be used by method fdb_remove_tun.
We expect to clean up after calling del_fdb_flow. It will be mainly
deleting a port from a bridge.
If you need, you may do some cleanup for a bridge.
:param tun_ofport: a port value to cleanup.
:param tunnel_type: a type of tunnel.
'''
pass
def get_agent_ports(self, fdb_entries, local_vlan_map):
for network_id, values in fdb_entries.items():
lvm = local_vlan_map.get(network_id)
agent_ports = values.get('ports') if lvm else {}
yield (lvm, agent_ports)
@log.log
def fdb_add_tun(self, context, lvm, agent_ports, ofports):
for remote_ip, ports in agent_ports.items():
# Ensure we have a tunnel port with this remote agent
ofport = ofports[lvm.network_type].get(remote_ip)
if not ofport:
ofport = self.setup_tunnel_port(remote_ip, lvm.network_type)
if ofport == 0:
continue
for port in ports:
self.add_fdb_flow(port, remote_ip, lvm, ofport)
@log.log
def fdb_remove_tun(self, context, lvm, agent_ports, ofports):
for remote_ip, ports in agent_ports.items():
ofport = ofports[lvm.network_type].get(remote_ip)
if not ofport:
continue
for port in ports:
self.del_fdb_flow(port, remote_ip, lvm, ofport)
if port == n_const.FLOODING_ENTRY:
# Check if this tunnel port is still used
self.cleanup_tunnel_port(ofport, lvm.network_type)
@log.log
def fdb_update(self, context, fdb_entries):
'''Call methods named '_fdb_<action>'.
This method assumes that methods '_fdb_<action>' are defined in class.
Currently the following actions are available.
chg_ip
'''
for action, values in fdb_entries.items():
method = '_fdb_' + action
if not hasattr(self, method):
raise NotImplementedError()
getattr(self, method)(context, values)

View File

@ -20,4 +20,5 @@
from neutron.common import constants
SUPPORTED_AGENT_TYPES = [constants.AGENT_TYPE_OVS,
constants.AGENT_TYPE_LINUXBRIDGE]
constants.AGENT_TYPE_LINUXBRIDGE,
constants.AGENT_TYPE_OFA]

View File

@ -26,6 +26,7 @@ from ryu.base import app_manager
from ryu.lib import hub
from ryu.ofproto import ofproto_v1_3 as ryu_ofp13
from neutron.agent import l2population_rpc
from neutron.agent.linux import ip_lib
from neutron.agent.linux import ovs_lib
from neutron.agent.linux import polling
@ -161,13 +162,16 @@ class OFANeutronAgentRyuApp(app_manager.RyuApp):
class OFANeutronAgent(n_rpc.RpcCallback,
sg_rpc.SecurityGroupAgentRpcCallbackMixin):
sg_rpc.SecurityGroupAgentRpcCallbackMixin,
l2population_rpc.L2populationRpcCallBackTunnelMixin):
"""A agent for OpenFlow Agent ML2 mechanism driver.
OFANeutronAgent is a OpenFlow Agent agent for a ML2 plugin.
This is as a ryu application thread.
This has the following features.
- An agent acts as an OpenFlow controller on each compute nodes.
- OpenFlow 1.3 (vendor agnostic unlike OVS extensions).
- l2-population is mandatory.
"""
# history
@ -178,8 +182,7 @@ class OFANeutronAgent(n_rpc.RpcCallback,
def __init__(self, ryuapp, integ_br, tun_br, local_ip,
bridge_mappings, root_helper,
polling_interval, tunnel_types=None,
veth_mtu=None, l2_population=False,
minimize_polling=False,
veth_mtu=None, minimize_polling=False,
ovsdb_monitor_respawn_interval=(
constants.DEFAULT_OVSDBMON_RESPAWN)):
"""Constructor.
@ -208,7 +211,6 @@ class OFANeutronAgent(n_rpc.RpcCallback,
self.available_local_vlans = set(xrange(n_const.MIN_VLAN_TAG,
n_const.MAX_VLAN_TAG))
self.tunnel_types = tunnel_types or []
self.l2_pop = l2_population
self.agent_state = {
'binary': 'neutron-ofa-agent',
'host': cfg.CONF.host,
@ -216,7 +218,7 @@ class OFANeutronAgent(n_rpc.RpcCallback,
'configurations': {'bridge_mappings': bridge_mappings,
'tunnel_types': self.tunnel_types,
'tunneling_ip': local_ip,
'l2_population': self.l2_pop},
'l2_population': True},
'agent_type': n_const.AGENT_TYPE_OFA,
'start_flag': True}
@ -291,8 +293,8 @@ class OFANeutronAgent(n_rpc.RpcCallback,
# Define the listening consumers for the agent
consumers = [[topics.PORT, topics.UPDATE],
[topics.NETWORK, topics.DELETE],
[constants.TUNNEL, topics.UPDATE],
[topics.SECURITY_GROUP, topics.UPDATE]]
[topics.SECURITY_GROUP, topics.UPDATE],
[topics.L2POPULATION, topics.UPDATE, cfg.CONF.host]]
self.connection = agent_rpc.create_consumers(self.endpoints,
self.topic,
consumers)
@ -341,46 +343,101 @@ class OFANeutronAgent(n_rpc.RpcCallback,
# they are not used since there is no guarantee the notifications
# are processed in the same order as the relevant API requests
self.updated_ports.add(ports.get_normalized_port_name(port['id']))
LOG.debug(_("port_update received port %s"), port['id'])
LOG.debug("port_update received port %s", port['id'])
def tunnel_update(self, context, **kwargs):
LOG.debug(_("tunnel_update received"))
if not self.enable_tunneling:
return
tunnel_ip = kwargs.get('tunnel_ip')
tunnel_type = kwargs.get('tunnel_type')
if not tunnel_type:
LOG.error(_("No tunnel_type specified, cannot create tunnels"))
return
if tunnel_type not in self.tunnel_types:
LOG.error(_("tunnel_type %s not supported by agent"), tunnel_type)
return
if tunnel_ip == self.local_ip:
return
tun_name = self._create_tunnel_port_name(tunnel_type, tunnel_ip)
if not tun_name:
return
self.setup_tunnel_port(tun_name, tunnel_ip, tunnel_type)
def fdb_add(self, context, fdb_entries):
LOG.debug("fdb_add received")
for lvm, agent_ports in self.get_agent_ports(fdb_entries,
self.local_vlan_map):
agent_ports.pop(self.local_ip, None)
if len(agent_ports):
self.fdb_add_tun(context, lvm, agent_ports,
self.tun_br_ofports)
def _provision_local_vlan_outbound_for_tunnel(self, lvid,
segmentation_id, ofports):
br = self.tun_br
match = br.ofparser.OFPMatch(
vlan_vid=int(lvid) | ryu_ofp13.OFPVID_PRESENT)
actions = [br.ofparser.OFPActionPopVlan(),
br.ofparser.OFPActionSetField(
tunnel_id=int(segmentation_id))]
for ofport in ofports:
actions.append(br.ofparser.OFPActionOutput(ofport, 0))
instructions = [br.ofparser.OFPInstructionActions(
ryu_ofp13.OFPIT_APPLY_ACTIONS, actions)]
msg = br.ofparser.OFPFlowMod(
br.datapath,
table_id=constants.FLOOD_TO_TUN,
priority=1,
match=match, instructions=instructions)
def fdb_remove(self, context, fdb_entries):
LOG.debug("fdb_remove received")
for lvm, agent_ports in self.get_agent_ports(fdb_entries,
self.local_vlan_map):
agent_ports.pop(self.local_ip, None)
if len(agent_ports):
self.fdb_remove_tun(context, lvm, agent_ports,
self.tun_br_ofports)
def _add_fdb_flooding_flow(self, lvm):
datapath = self.tun_br.datapath
ofp = datapath.ofproto
ofpp = datapath.ofproto_parser
match = ofpp.OFPMatch(
vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT)
actions = [ofpp.OFPActionPopVlan(),
ofpp.OFPActionSetField(
tunnel_id=int(lvm.segmentation_id))]
for tun_ofport in lvm.tun_ofports:
actions.append(ofpp.OFPActionOutput(int(tun_ofport), 0))
instructions = [ofpp.OFPInstructionActions(
ofp.OFPIT_APPLY_ACTIONS, actions)]
msg = ofpp.OFPFlowMod(datapath,
table_id=constants.FLOOD_TO_TUN,
command=ofp.OFPFC_ADD,
priority=1,
match=match, instructions=instructions)
self.ryu_send_msg(msg)
def add_fdb_flow(self, port_info, remote_ip, lvm, ofport):
datapath = self.tun_br.datapath
ofp = datapath.ofproto
ofpp = datapath.ofproto_parser
if port_info == n_const.FLOODING_ENTRY:
lvm.tun_ofports.add(ofport)
self._add_fdb_flooding_flow(lvm)
else:
match = ofpp.OFPMatch(
vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT,
eth_dst=port_info[0])
actions = [ofpp.OFPActionPopVlan(),
ofpp.OFPActionSetField(
tunnel_id=int(lvm.segmentation_id)),
ofpp.OFPActionOutput(int(ofport), 0)]
instructions = [ofpp.OFPInstructionActions(
ofp.OFPIT_APPLY_ACTIONS, actions)]
msg = ofpp.OFPFlowMod(datapath,
table_id=constants.UCAST_TO_TUN,
command=ofp.OFPFC_ADD,
priority=2,
match=match, instructions=instructions)
self.ryu_send_msg(msg)
def del_fdb_flow(self, port_info, remote_ip, lvm, ofport):
datapath = self.tun_br.datapath
ofp = datapath.ofproto
ofpp = datapath.ofproto_parser
if port_info == n_const.FLOODING_ENTRY:
lvm.tun_ofports.remove(ofport)
if len(lvm.tun_ofports) > 0:
self._add_fdb_flooding_flow(lvm)
else:
# This local vlan doesn't require any more tunelling
match = ofpp.OFPMatch(
vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT)
msg = ofpp.OFPFlowMod(datapath,
table_id=constants.FLOOD_TO_TUN,
command=ofp.OFPFC_DELETE,
out_group=ofp.OFPG_ANY,
out_port=ofp.OFPP_ANY,
match=match)
self.ryu_send_msg(msg)
else:
match = ofpp.OFPMatch(
vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT,
eth_dst=port_info[0])
msg = ofpp.OFPFlowMod(datapath,
table_id=constants.UCAST_TO_TUN,
command=ofp.OFPFC_DELETE,
out_group=ofp.OFPG_ANY,
out_port=ofp.OFPP_ANY,
match=match)
self.ryu_send_msg(msg)
def _provision_local_vlan_inbound_for_tunnel(self, lvid, network_type,
segmentation_id):
br = self.tun_br
@ -404,11 +461,6 @@ class OFANeutronAgent(n_rpc.RpcCallback,
self.ryu_send_msg(msg)
def _local_vlan_for_tunnel(self, lvid, network_type, segmentation_id):
ofports = [int(ofport) for ofport in
self.tun_br_ofports[network_type].values()]
if ofports:
self._provision_local_vlan_outbound_for_tunnel(
lvid, segmentation_id, ofports)
self._provision_local_vlan_inbound_for_tunnel(lvid, network_type,
segmentation_id)
@ -588,6 +640,9 @@ class OFANeutronAgent(n_rpc.RpcCallback,
out_port=ryu_ofp13.OFPP_ANY,
match=match)
self.ryu_send_msg(msg)
# Try to remove tunnel ports if not used by other networks
for ofport in lvm.tun_ofports:
self.cleanup_tunnel_port(ofport, lvm.network_type)
elif lvm.network_type in (p_const.TYPE_FLAT, p_const.TYPE_VLAN):
if lvm.physical_network in self.phys_brs:
self._reclaim_local_vlan_outbound(lvm)
@ -1015,7 +1070,7 @@ class OFANeutronAgent(n_rpc.RpcCallback,
else:
LOG.debug(_("No VIF port for port %s defined on agent."), port_id)
def setup_tunnel_port(self, port_name, remote_ip, tunnel_type):
def _setup_tunnel_port(self, port_name, remote_ip, tunnel_type):
ofport = self.tun_br.add_tunnel_port(port_name,
remote_ip,
self.local_ip,
@ -1044,36 +1099,45 @@ class OFANeutronAgent(n_rpc.RpcCallback,
match=match,
instructions=instructions)
self.ryu_send_msg(msg)
ofports = [int(p) for p in self.tun_br_ofports[tunnel_type].values()]
if ofports:
# Update flooding flows to include the new tunnel
for network_id, vlan_mapping in self.local_vlan_map.iteritems():
if vlan_mapping.network_type == tunnel_type:
match = self.tun_br.ofparser.OFPMatch(
vlan_vid=int(vlan_mapping.vlan) |
ryu_ofp13.OFPVID_PRESENT)
actions = [
self.tun_br.ofparser.OFPActionPopVlan(),
self.tun_br.ofparser.OFPActionSetField(
tunnel_id=int(vlan_mapping.segmentation_id))]
actions.extend(
self.tun_br.ofparser.OFPActionOutput(p, 0)
for p in ofports
)
instructions = [
self.tun_br.ofparser.OFPInstructionActions(
ryu_ofp13.OFPIT_APPLY_ACTIONS,
actions)]
msg = self.tun_br.ofparser.OFPFlowMod(
self.tun_br.datapath,
table_id=constants.FLOOD_TO_TUN,
priority=1,
match=match,
instructions=instructions)
self.ryu_send_msg(msg)
return ofport
def setup_tunnel_port(self, remote_ip, network_type):
port_name = self._create_tunnel_port_name(network_type, remote_ip)
if not port_name:
return 0
ofport = self._setup_tunnel_port(port_name,
remote_ip,
network_type)
return ofport
def _remove_tunnel_port(self, tun_ofport, tunnel_type):
datapath = self.tun_br.datapath
ofp = datapath.ofproto
ofpp = datapath.ofproto_parser
for remote_ip, ofport in self.tun_br_ofports[tunnel_type].items():
if ofport == tun_ofport:
port_name = self._create_tunnel_port_name(tunnel_type,
remote_ip)
if port_name:
self.tun_br.delete_port(port_name)
match = ofpp.OFPMatch(in_port=int(ofport))
msg = ofpp.OFPFlowMod(datapath,
command=ofp.OFPFC_DELETE,
out_group=ofp.OFPG_ANY,
out_port=ofp.OFPP_ANY,
match=match)
self.ryu_send_msg(msg)
self.tun_br_ofports[tunnel_type].pop(remote_ip, None)
def cleanup_tunnel_port(self, tun_ofport, tunnel_type):
# Check if this tunnel port is still used
for lvm in self.local_vlan_map.values():
if tun_ofport in lvm.tun_ofports:
break
# If not, remove it
else:
self._remove_tunnel_port(tun_ofport, tunnel_type)
def treat_devices_added_or_updated(self, devices):
resync = False
all_ports = dict((p.normalized_port_name(), p) for p in
@ -1245,19 +1309,9 @@ class OFANeutronAgent(n_rpc.RpcCallback,
resync = False
try:
for tunnel_type in self.tunnel_types:
details = self.plugin_rpc.tunnel_sync(self.context,
self.local_ip,
tunnel_type)
tunnels = details['tunnels']
for tunnel in tunnels:
if self.local_ip != tunnel['ip_address']:
tun_name = self._create_tunnel_port_name(
tunnel_type, tunnel['ip_address'])
if not tun_name:
continue
self.setup_tunnel_port(tun_name,
tunnel['ip_address'],
tunnel_type)
self.plugin_rpc.tunnel_sync(self.context,
self.local_ip,
tunnel_type)
except Exception as e:
LOG.debug(_("Unable to sync tunnel IP %(local_ip)s: %(e)s"),
{'local_ip': self.local_ip, 'e': e})
@ -1428,7 +1482,6 @@ def create_agent_config_map(config):
minimize_polling=config.AGENT.minimize_polling,
tunnel_types=config.AGENT.tunnel_types,
veth_mtu=config.AGENT.veth_mtu,
l2_population=False,
ovsdb_monitor_respawn_interval=constants.DEFAULT_OVSDBMON_RESPAWN,
)

View File

@ -97,7 +97,7 @@ class OVSSecurityGroupAgent(sg_rpc.SecurityGroupAgentRpcMixin):
class OVSNeutronAgent(n_rpc.RpcCallback,
sg_rpc.SecurityGroupAgentRpcCallbackMixin,
l2population_rpc.L2populationRpcCallBackMixin,
l2population_rpc.L2populationRpcCallBackTunnelMixin,
dvr_rpc.DVRAgentRpcCallbackMixin):
'''Implements OVS-based tunneling, VLANs and flat networks.
@ -348,61 +348,35 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
return
tun_name = '%s-%s' % (tunnel_type, tunnel_id)
if not self.l2_pop:
self.setup_tunnel_port(tun_name, tunnel_ip, tunnel_type)
self._setup_tunnel_port(tun_name, tunnel_ip, tunnel_type)
def fdb_add(self, context, fdb_entries):
LOG.debug(_("fdb_add received"))
for network_id, values in fdb_entries.items():
lvm = self.local_vlan_map.get(network_id)
if not lvm:
# Agent doesn't manage any port in this network
continue
agent_ports = values.get('ports')
LOG.debug("fdb_add received")
for lvm, agent_ports in self.get_agent_ports(fdb_entries,
self.local_vlan_map):
agent_ports.pop(self.local_ip, None)
if len(agent_ports):
if not self.enable_distributed_routing:
self.tun_br.defer_apply_on()
for agent_ip, ports in agent_ports.items():
# Ensure we have a tunnel port with this remote agent
ofport = self.tun_br_ofports[
lvm.network_type].get(agent_ip)
if not ofport:
remote_ip_hex = self.get_ip_in_hex(agent_ip)
if not remote_ip_hex:
continue
port_name = '%s-%s' % (lvm.network_type, remote_ip_hex)
ofport = self.setup_tunnel_port(port_name, agent_ip,
lvm.network_type)
if ofport == 0:
continue
for port in ports:
self._add_fdb_flow(port, agent_ip, lvm, ofport)
self.fdb_add_tun(context, lvm, agent_ports,
self.tun_br_ofports)
if not self.enable_distributed_routing:
self.tun_br.defer_apply_off()
def fdb_remove(self, context, fdb_entries):
LOG.debug(_("fdb_remove received"))
for network_id, values in fdb_entries.items():
lvm = self.local_vlan_map.get(network_id)
if not lvm:
# Agent doesn't manage any more ports in this network
continue
agent_ports = values.get('ports')
LOG.debug("fdb_remove received")
for lvm, agent_ports in self.get_agent_ports(fdb_entries,
self.local_vlan_map):
agent_ports.pop(self.local_ip, None)
if len(agent_ports):
if not self.enable_distributed_routing:
self.tun_br.defer_apply_on()
for agent_ip, ports in agent_ports.items():
ofport = self.tun_br_ofports[
lvm.network_type].get(agent_ip)
if not ofport:
continue
for port in ports:
self._del_fdb_flow(port, agent_ip, lvm, ofport)
self.fdb_remove_tun(context, lvm, agent_ports,
self.tun_br_ofports)
if not self.enable_distributed_routing:
self.tun_br.defer_apply_off()
def _add_fdb_flow(self, port_info, agent_ip, lvm, ofport):
def add_fdb_flow(self, port_info, remote_ip, lvm, ofport):
if port_info == q_const.FLOODING_ENTRY:
lvm.tun_ofports.add(ofport)
ofports = ','.join(lvm.tun_ofports)
@ -422,7 +396,7 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
"output:%s" %
(lvm.segmentation_id, ofport))
def _del_fdb_flow(self, port_info, agent_ip, lvm, ofport):
def del_fdb_flow(self, port_info, remote_ip, lvm, ofport):
if port_info == q_const.FLOODING_ENTRY:
lvm.tun_ofports.remove(ofport)
if len(lvm.tun_ofports) > 0:
@ -436,8 +410,6 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
# This local vlan doesn't require any more tunnelling
self.tun_br.delete_flows(table=constants.FLOOD_TO_TUN,
dl_vlan=lvm.vlan)
# Check if this tunnel port is still used
self.cleanup_tunnel_port(ofport, lvm.network_type)
else:
self._set_arp_responder('remove', lvm.vlan, port_info[0],
port_info[1])
@ -486,15 +458,6 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
for mac, ip in before:
self._set_arp_responder('remove', lvm.vlan, mac, ip)
def fdb_update(self, context, fdb_entries):
LOG.debug(_("fdb_update received"))
for action, values in fdb_entries.items():
method = '_fdb_' + action
if not hasattr(self, method):
raise NotImplementedError()
getattr(self, method)(context, values)
def _set_arp_responder(self, action, lvid, mac_str, ip_str):
'''Set the ARP respond entry.
@ -1111,7 +1074,7 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
else:
LOG.debug(_("No VIF port for port %s defined on agent."), port_id)
def setup_tunnel_port(self, port_name, remote_ip, tunnel_type):
def _setup_tunnel_port(self, port_name, remote_ip, tunnel_type):
ofport = self.tun_br.add_tunnel_port(port_name,
remote_ip,
self.local_ip,
@ -1150,6 +1113,16 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
ofports))
return ofport
def setup_tunnel_port(self, remote_ip, network_type):
remote_ip_hex = self.get_ip_in_hex(remote_ip)
if not remote_ip_hex:
return 0
port_name = '%s-%s' % (network_type, remote_ip_hex)
ofport = self._setup_tunnel_port(port_name,
remote_ip,
network_type)
return ofport
def cleanup_tunnel_port(self, tun_ofport, tunnel_type):
# Check if this tunnel port is still used
for lvm in self.local_vlan_map.values():
@ -1393,9 +1366,8 @@ class OVSNeutronAgent(n_rpc.RpcCallback,
continue
tun_name = '%s-%s' % (tunnel_type,
tunnel_id or remote_ip_hex)
self.setup_tunnel_port(tun_name,
tunnel['ip_address'],
tunnel_type)
self._setup_tunnel_port(
tun_name, tunnel['ip_address'], tunnel_type)
except Exception as e:
LOG.debug(_("Unable to sync tunnel IP %(local_ip)s: %(e)s"),
{'local_ip': self.local_ip, 'e': e})

View File

@ -0,0 +1,140 @@
# Copyright (C) 2014 VA Linux Systems Japan K.K.
#
# 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.
# @author: Fumihiko Kakuma, VA Linux Systems Japan K.K.
import collections
from neutron.agent import l2population_rpc
from neutron.plugins.openvswitch.agent import ovs_neutron_agent
from neutron.tests import base
class FakeNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin):
def fdb_add(self, context, fdb_entries):
pass
def fdb_remove(self, context, fdb_entries):
pass
def add_fdb_flow(self, port_info, remote_ip, lvm, ofport):
pass
def del_fdb_flow(self, port_info, remote_ip, lvm, ofport):
pass
def setup_tunnel_port(self, remote_ip, network_type):
pass
def cleanup_tunnel_port(self, tun_ofport, tunnel_type):
pass
class TestL2populationRpcCallBackTunnelMixinBase(base.BaseTestCase):
def setUp(self):
super(TestL2populationRpcCallBackTunnelMixinBase, self).setUp()
self.fakeagent = FakeNeutronAgent()
Port = collections.namedtuple('Port', 'ip, ofport')
LVM = collections.namedtuple(
'LVM', 'net, vlan, phys, segid, mac, ip, vif, port')
self.local_ip = '127.0.0.1'
self.type_gre = 'gre'
self.ports = [Port(ip='10.1.0.1', ofport='ofport1'),
Port(ip='10.1.0.2', ofport='ofport2'),
Port(ip='10.1.0.3', ofport='ofport3')]
self.ofports = {
self.type_gre: {
self.ports[0].ip: self.ports[0].ofport,
self.ports[1].ip: self.ports[1].ofport,
self.ports[2].ip: self.ports[2].ofport,
}
}
self.lvms = [LVM(net='net1', vlan=1, phys='phys1', segid='tun1',
mac='mac1', ip='1.1.1.1', vif='vifid1',
port='port1'),
LVM(net='net2', vlan=2, phys='phys2', segid='tun2',
mac='mac2', ip='2.2.2.2', vif='vifid2',
port='port2'),
LVM(net='net3', vlan=3, phys='phys3', segid='tun3',
mac='mac3', ip='3.3.3.3', vif='vifid3',
port='port3')]
self.agent_ports = {
self.ports[0].ip: [[self.lvms[0].mac, self.lvms[0].ip]],
self.ports[1].ip: [[self.lvms[1].mac, self.lvms[1].ip]],
self.ports[2].ip: [[self.lvms[2].mac, self.lvms[2].ip]],
}
self.fdb_entries1 = {
self.lvms[0].net: {
'network_type': self.type_gre,
'segment_id': self.lvms[0].segid,
'ports': {
self.local_ip: [],
self.ports[0].ip: [[self.lvms[0].mac, self.lvms[0].ip]]},
},
self.lvms[1].net: {
'network_type': self.type_gre,
'segment_id': self.lvms[1].segid,
'ports': {
self.local_ip: [],
self.ports[1].ip: [[self.lvms[1].mac, self.lvms[1].ip]]},
},
self.lvms[2].net: {
'network_type': self.type_gre,
'segment_id': self.lvms[2].segid,
'ports': {
self.local_ip: [],
self.ports[2].ip: [[self.lvms[2].mac, self.lvms[2].ip]]},
},
}
self.lvm1 = ovs_neutron_agent.LocalVLANMapping(
self.lvms[0].vlan, self.type_gre, self.lvms[0].phys,
self.lvms[0].segid, {self.lvms[0].vif: self.lvms[0].port})
self.lvm2 = ovs_neutron_agent.LocalVLANMapping(
self.lvms[1].vlan, self.type_gre, self.lvms[1].phys,
self.lvms[1].segid, {self.lvms[1].vif: self.lvms[1].port})
self.lvm3 = ovs_neutron_agent.LocalVLANMapping(
self.lvms[2].vlan, self.type_gre, self.lvms[2].phys,
self.lvms[2].segid, {self.lvms[2].vif: self.lvms[2].port})
self.local_vlan_map1 = {
self.lvms[0].net: self.lvm1,
self.lvms[1].net: self.lvm2,
self.lvms[2].net: self.lvm3,
}
self.upd_fdb_entry1_val = {
self.lvms[0].net: {
self.ports[0].ip: {
'before': [[self.lvms[0].mac, self.lvms[0].ip]],
'after': [[self.lvms[1].mac, self.lvms[1].ip]],
},
self.ports[1].ip: {
'before': [[self.lvms[0].mac, self.lvms[0].ip]],
'after': [[self.lvms[1].mac, self.lvms[1].ip]],
},
},
self.lvms[1].net: {
self.ports[2].ip: {
'before': [[self.lvms[0].mac, self.lvms[0].ip]],
'after': [[self.lvms[2].mac, self.lvms[2].ip]],
},
},
}
self.upd_fdb_entry1 = {'chg_ip': self.upd_fdb_entry1_val}

View File

@ -0,0 +1,190 @@
# Copyright (C) 2014 VA Linux Systems Japan K.K.
#
# 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.
# @author: Fumihiko Kakuma, VA Linux Systems Japan K.K.
import contextlib
import mock
from neutron.common import constants as n_const
from neutron.tests.unit.agent import l2population_rpc_base
class TestL2populationRpcCallBackTunnelMixin(
l2population_rpc_base.TestL2populationRpcCallBackTunnelMixinBase):
def test_get_agent_ports_no_data(self):
for lvm, agent_ports in self.fakeagent.get_agent_ports(
self.fdb_entries1, {}):
self.assertIsNone(lvm)
self.assertEqual({}, agent_ports)
def test_get_agent_ports_non_existence_key_in_lvm(self):
results = {}
del self.local_vlan_map1[self.lvms[1].net]
for lvm, agent_ports in self.fakeagent.get_agent_ports(
self.fdb_entries1, self.local_vlan_map1):
results[lvm] = agent_ports
expected = {
self.lvm1: {
self.ports[0].ip: [[self.lvms[0].mac, self.lvms[0].ip]],
self.local_ip: []},
None: {},
self.lvm3: {
self.ports[2].ip: [[self.lvms[2].mac, self.lvms[2].ip]],
self.local_ip: []},
}
self.assertEqual(expected, results)
def test_get_agent_ports_no_agent_ports(self):
results = {}
self.fdb_entries1[self.lvms[1].net]['ports'] = {}
for lvm, agent_ports in self.fakeagent.get_agent_ports(
self.fdb_entries1, self.local_vlan_map1):
results[lvm] = agent_ports
expected = {
self.lvm1: {
self.ports[0].ip: [[self.lvms[0].mac, self.lvms[0].ip]],
self.local_ip: []},
self.lvm2: {},
self.lvm3: {
self.ports[2].ip: [[self.lvms[2].mac, self.lvms[2].ip]],
self.local_ip: []},
}
self.assertEqual(expected, results)
def test_fdb_add_tun(self):
with contextlib.nested(
mock.patch.object(self.fakeagent, 'setup_tunnel_port'),
mock.patch.object(self.fakeagent, 'add_fdb_flow'),
) as (mock_setup_tunnel_port, mock_add_fdb_flow):
self.fakeagent.fdb_add_tun('context', self.lvm1,
self.agent_ports, self.ofports)
expected = [
mock.call([self.lvms[0].mac, self.lvms[0].ip], self.ports[0].ip,
self.lvm1, self.ports[0].ofport),
mock.call([self.lvms[1].mac, self.lvms[1].ip], self.ports[1].ip,
self.lvm1, self.ports[1].ofport),
mock.call([self.lvms[2].mac, self.lvms[2].ip], self.ports[2].ip,
self.lvm1, self.ports[2].ofport),
]
self.assertEqual(sorted(expected),
sorted(mock_add_fdb_flow.call_args_list))
def test_fdb_add_tun_non_existence_key_in_ofports(self):
ofport = self.lvm1.network_type + '0a0a0a0a'
del self.ofports[self.type_gre][self.ports[1].ip]
with contextlib.nested(
mock.patch.object(self.fakeagent, 'setup_tunnel_port',
return_value=ofport),
mock.patch.object(self.fakeagent, 'add_fdb_flow'),
) as (mock_setup_tunnel_port, mock_add_fdb_flow):
self.fakeagent.fdb_add_tun('context', self.lvm1,
self.agent_ports, self.ofports)
mock_setup_tunnel_port.assert_called_once_with(
self.ports[1].ip, self.lvm1.network_type)
expected = [
mock.call([self.lvms[0].mac, self.lvms[0].ip], self.ports[0].ip,
self.lvm1, self.ports[0].ofport),
mock.call([self.lvms[1].mac, self.lvms[1].ip], self.ports[1].ip,
self.lvm1, ofport),
mock.call([self.lvms[2].mac, self.lvms[2].ip], self.ports[2].ip,
self.lvm1, self.ports[2].ofport),
]
self.assertEqual(sorted(expected),
sorted(mock_add_fdb_flow.call_args_list))
def test_fdb_add_tun_unavailable_ofport(self):
del self.ofports[self.type_gre][self.ports[1].ip]
with contextlib.nested(
mock.patch.object(self.fakeagent, 'setup_tunnel_port',
return_value=0),
mock.patch.object(self.fakeagent, 'add_fdb_flow'),
) as (mock_setup_tunnel_port, mock_add_fdb_flow):
self.fakeagent.fdb_add_tun('context', self.lvm1,
self.agent_ports, self.ofports)
mock_setup_tunnel_port.assert_called_once_with(
self.ports[1].ip, self.lvm1.network_type)
expected = [
mock.call([self.lvms[0].mac, self.lvms[0].ip], self.ports[0].ip,
self.lvm1, self.ports[0].ofport),
mock.call([self.lvms[2].mac, self.lvms[2].ip], self.ports[2].ip,
self.lvm1, self.ports[2].ofport),
]
self.assertEqual(sorted(expected),
sorted(mock_add_fdb_flow.call_args_list))
def test_fdb_remove_tun(self):
with mock.patch.object(
self.fakeagent, 'del_fdb_flow') as mock_del_fdb_flow:
self.fakeagent.fdb_remove_tun('context', self.lvm1,
self.agent_ports, self.ofports)
expected = [
mock.call([self.lvms[0].mac, self.lvms[0].ip], self.ports[0].ip,
self.lvm1, self.ports[0].ofport),
mock.call([self.lvms[1].mac, self.lvms[1].ip], self.ports[1].ip,
self.lvm1, self.ports[1].ofport),
mock.call([self.lvms[2].mac, self.lvms[2].ip], self.ports[2].ip,
self.lvm1, self.ports[2].ofport),
]
self.assertEqual(sorted(expected),
sorted(mock_del_fdb_flow.call_args_list))
def test_fdb_remove_tun_flooding_entry(self):
self.agent_ports[self.ports[1].ip] = [n_const.FLOODING_ENTRY]
with contextlib.nested(
mock.patch.object(self.fakeagent, 'del_fdb_flow'),
mock.patch.object(self.fakeagent, 'cleanup_tunnel_port'),
) as (mock_del_fdb_flow, mock_cleanup_tunnel_port):
self.fakeagent.fdb_remove_tun('context', self.lvm1,
self.agent_ports, self.ofports)
expected = [
mock.call([self.lvms[0].mac, self.lvms[0].ip], self.ports[0].ip,
self.lvm1, self.ports[0].ofport),
mock.call([n_const.FLOODING_ENTRY[0], n_const.FLOODING_ENTRY[1]],
self.ports[1].ip, self.lvm1, self.ports[1].ofport),
mock.call([self.lvms[2].mac, self.lvms[2].ip], self.ports[2].ip,
self.lvm1, self.ports[2].ofport),
]
self.assertEqual(sorted(expected),
sorted(mock_del_fdb_flow.call_args_list))
mock_cleanup_tunnel_port.assert_called_once_with(
self.ports[1].ofport, self.lvm1.network_type)
def test_fdb_remove_tun_non_existence_key_in_ofports(self):
del self.ofports[self.type_gre][self.ports[1].ip]
with mock.patch.object(
self.fakeagent, 'del_fdb_flow') as mock_del_fdb_flow:
self.fakeagent.fdb_remove_tun('context', self.lvm1,
self.agent_ports, self.ofports)
expected = [
mock.call([self.lvms[0].mac, self.lvms[0].ip], self.ports[0].ip,
self.lvm1, self.ports[0].ofport),
mock.call([self.lvms[2].mac, self.lvms[2].ip], self.ports[2].ip,
self.lvm1, self.ports[2].ofport),
]
self.assertEqual(sorted(expected),
sorted(mock_del_fdb_flow.call_args_list))
def test_fdb_update(self):
fake__fdb_chg_ip = mock.Mock()
self.fakeagent._fdb_chg_ip = fake__fdb_chg_ip
self.fakeagent.fdb_update('context', self.upd_fdb_entry1)
fake__fdb_chg_ip.assert_called_once_with(
'context', self.upd_fdb_entry1_val)
def test_fdb_update_non_existence_method(self):
self.assertRaises(NotImplementedError,
self.fakeagent.fdb_update,
'context', self.upd_fdb_entry1)

View File

@ -18,6 +18,7 @@
# @author: Fumihiko Kakuma, VA Linux Systems Japan K.K.
# @author: YAMAMOTO Takashi, VA Linux Systems Japan K.K.
import collections
import contextlib
import mock
@ -27,6 +28,7 @@ import testtools
from neutron.agent.linux import ip_lib
from neutron.agent.linux import utils
from neutron.common import constants as n_const
from neutron.openstack.common import importutils
from neutron.plugins.common import constants as p_const
from neutron.plugins.openvswitch.common import constants
@ -258,27 +260,36 @@ class TestOFANeutronAgent(OFAAgentTestCase):
'FixedIntervalLoopingCall',
new=MockFixedIntervalLoopingCall)):
self.agent = self.mod_agent.OFANeutronAgent(self.ryuapp, **kwargs)
self.agent.tun_br = _mk_test_br('tun_br')
self.datapath = mock.Mock()
self.ofparser = mock.Mock()
self.agent.phys_brs['phys-net1'] = _mk_test_br('phys_br1')
self.agent.phys_ofports['phys-net1'] = 777
self.agent.int_ofports['phys-net1'] = 666
self.datapath.ofparser = self.ofparser
self.ofparser.OFPMatch = mock.Mock()
self.ofparser.OFPMatch.return_value = mock.Mock()
self.ofparser.OFPFlowMod = mock.Mock()
self.ofparser.OFPFlowMod.return_value = mock.Mock()
self.agent.int_br.ofparser = self.ofparser
self.agent.int_br.datapath = _mk_test_dp('int_br')
self.agent.sg_agent = mock.Mock()
self.int_dp = _mk_test_dp('int_br')
self.agent.int_br.ofparser = self.int_dp.ofproto_parser
self.agent.int_br.datapath = self.int_dp
self.agent.tun_br = _mk_test_br('tun_br')
self.agent.phys_brs['phys-net1'] = _mk_test_br('phys_br1')
self.agent.phys_ofports['phys-net1'] = 777
self.agent.int_ofports['phys-net1'] = 666
self.datapath = _mk_test_dp('phys_br')
def _create_tunnel_port_name(self, tunnel_ip, tunnel_type):
tunnel_ip_hex = '%08x' % netaddr.IPAddress(tunnel_ip, version=4)
return '%s-%s' % (tunnel_type, tunnel_ip_hex)
def _mock_port_bound(self, ofport=None, new_local_vlan=None,
old_local_vlan=None):
port = mock.Mock()
port.ofport = ofport
net_uuid = 'my-net-uuid'
ofp = self.agent.int_br.datapath.ofproto
ofpp = self.agent.int_br.datapath.ofproto_parser
expected_msg = ofpp.OFPFlowMod(
self.agent.int_br.datapath,
match=ofpp.OFPMatch(in_port=port.ofport),
table_id=ofp.OFPTT_ALL,
command=ofp.OFPFC_DELETE,
out_group=ofp.OFPG_ANY,
out_port=ofp.OFPP_ANY
)
if old_local_vlan is not None:
self.agent.local_vlan_map[net_uuid] = (
self.mod_agent.LocalVLANMapping(
@ -296,8 +307,7 @@ class TestOFANeutronAgent(OFAAgentTestCase):
set_ovs_db_func.assert_called_once_with(
"Port", mock.ANY, "tag", str(new_local_vlan))
if ofport != -1:
ryu_send_msg_func.assert_called_once_with(
self.ofparser.OFPFlowMod.return_value)
ryu_send_msg_func.assert_called_once_with(expected_msg)
else:
self.assertFalse(ryu_send_msg_func.called)
else:
@ -316,6 +326,12 @@ class TestOFANeutronAgent(OFAAgentTestCase):
def _test_port_dead(self, cur_tag=None):
port = mock.Mock()
port.ofport = 1
ofpp = self.agent.int_br.datapath.ofproto_parser
expected_msg = ofpp.OFPFlowMod(
self.agent.int_br.datapath,
priority=2,
match=ofpp.OFPMatch(in_port=port.ofport)
)
with contextlib.nested(
mock.patch.object(self.mod_agent.OVSBridge,
'set_db_attribute', return_value=True),
@ -331,8 +347,7 @@ class TestOFANeutronAgent(OFAAgentTestCase):
else:
set_ovs_db_func.assert_called_once_with(
"Port", mock.ANY, "tag", str(self.mod_agent.DEAD_VLAN_TAG))
ryu_send_msg_func.assert_called_once_with(
self.ofparser.OFPFlowMod.return_value)
ryu_send_msg_func.assert_called_once_with(expected_msg)
def test_port_dead(self):
self._test_port_dead()
@ -570,14 +585,17 @@ class TestOFANeutronAgent(OFAAgentTestCase):
)
def test_network_delete(self):
with mock.patch.object(self.agent,
"reclaim_local_vlan") as recl_fn:
with contextlib.nested(
mock.patch.object(self.agent, "reclaim_local_vlan"),
mock.patch.object(self.agent.tun_br, "cleanup_tunnel_port")
) as (recl_fn, clean_tun_fn):
self.agent.network_delete("unused_context",
network_id="123")
self.assertFalse(recl_fn.called)
self.agent.local_vlan_map["123"] = "LVM object"
self.agent.network_delete("unused_context",
network_id="123")
self.assertFalse(clean_tun_fn.called)
recl_fn.assert_called_with("123")
def test_port_update(self):
@ -655,6 +673,146 @@ class TestOFANeutronAgent(OFAAgentTestCase):
self.agent.port_unbound("vif3", "netuid12345")
self.assertEqual(reclvl_fn.call_count, 2)
def _prepare_l2_pop_ofports(self):
LVM = collections.namedtuple('LVM', 'net, vlan, segid, ip')
self.lvms = [LVM(net='net1', vlan=11, segid='21', ip='1.1.1.1'),
LVM(net='net2', vlan=12, segid='22', ip='2.2.2.2')]
self.tunnel_type = 'gre'
self.tun_name1 = self._create_tunnel_port_name(self.lvms[0].ip,
self.tunnel_type)
self.tun_name2 = self._create_tunnel_port_name(self.lvms[1].ip,
self.tunnel_type)
lvm1 = mock.Mock()
lvm1.network_type = self.tunnel_type
lvm1.vlan = self.lvms[0].vlan
lvm1.segmentation_id = self.lvms[0].segid
lvm1.tun_ofports = set(['1'])
lvm2 = mock.Mock()
lvm2.network_type = self.tunnel_type
lvm2.vlan = self.lvms[1].vlan
lvm2.segmentation_id = self.lvms[1].segid
lvm2.tun_ofports = set(['1', '2'])
self.agent.local_vlan_map = {self.lvms[0].net: lvm1,
self.lvms[1].net: lvm2}
self.agent.tun_br_ofports = {self.tunnel_type:
{self.lvms[0].ip: '1',
self.lvms[1].ip: '2'}}
def test_fdb_ignore_network(self):
self._prepare_l2_pop_ofports()
fdb_entry = {'net3': {}}
with contextlib.nested(
mock.patch.object(self.agent, 'ryu_send_msg'),
mock.patch.object(self.agent, '_setup_tunnel_port'),
mock.patch.object(self.agent, 'cleanup_tunnel_port')
) as (ryu_send_msg_fn, add_tun_fn, clean_tun_fn):
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(add_tun_fn.called)
self.agent.fdb_remove(None, fdb_entry)
self.assertFalse(clean_tun_fn.called)
self.assertFalse(ryu_send_msg_fn.called)
def test_fdb_ignore_self(self):
self._prepare_l2_pop_ofports()
self.agent.local_ip = 'agent_ip'
fdb_entry = {self.lvms[1].net:
{'network_type': self.tunnel_type,
'segment_id': 'tun2',
'ports':
{'agent_ip':
[['mac', 'ip'],
n_const.FLOODING_ENTRY]}}}
with mock.patch.object(self.agent.tun_br,
"defer_apply_on") as defer_fn:
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(defer_fn.called)
self.agent.fdb_remove(None, fdb_entry)
self.assertFalse(defer_fn.called)
def test_fdb_add_flows(self):
self._prepare_l2_pop_ofports()
fdb_entry = {self.lvms[0].net:
{'network_type': self.tunnel_type,
'segment_id': 'tun1',
'ports':
{self.lvms[1].ip:
[['mac', 'ip'],
n_const.FLOODING_ENTRY]}}}
with contextlib.nested(
mock.patch.object(self.agent, 'ryu_send_msg'),
mock.patch.object(self.agent.tun_br, '_setup_tunnel_port'),
) as (ryu_send_msg_fn, add_tun_fn):
add_tun_fn.return_value = '2'
self.agent.fdb_add(None, fdb_entry)
self.assertEqual(ryu_send_msg_fn.call_count, 2)
def test_fdb_del_flows(self):
self._prepare_l2_pop_ofports()
fdb_entry = {self.lvms[1].net:
{'network_type': self.tunnel_type,
'segment_id': 'tun2',
'ports':
{self.lvms[1].ip:
[['mac', 'ip'],
n_const.FLOODING_ENTRY]}}}
with mock.patch.object(self.agent,
'ryu_send_msg') as ryu_send_msg_fn:
self.agent.fdb_remove(None, fdb_entry)
self.assertEqual(ryu_send_msg_fn.call_count, 3)
def test_fdb_add_port(self):
self._prepare_l2_pop_ofports()
tunnel_ip = '10.10.10.10'
tun_name = self._create_tunnel_port_name(tunnel_ip,
self.tunnel_type)
fdb_entry = {self.lvms[0].net:
{'network_type': self.tunnel_type,
'segment_id': 'tun1',
'ports': {self.lvms[0].ip: [['mac', 'ip']]}}}
with contextlib.nested(
mock.patch.object(self.agent, 'ryu_send_msg'),
mock.patch.object(self.agent, '_setup_tunnel_port')
) as (ryu_send_msg_fn, add_tun_fn):
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(add_tun_fn.called)
fdb_entry[self.lvms[0].net]['ports'][tunnel_ip] = [['mac', 'ip']]
self.agent.fdb_add(None, fdb_entry)
add_tun_fn.assert_called_with(
tun_name, tunnel_ip, self.tunnel_type)
def test_fdb_del_port(self):
self._prepare_l2_pop_ofports()
fdb_entry = {self.lvms[1].net:
{'network_type': self.tunnel_type,
'segment_id': 'tun2',
'ports': {self.lvms[1].ip: [n_const.FLOODING_ENTRY]}}}
with contextlib.nested(
mock.patch.object(self.agent, 'ryu_send_msg'),
mock.patch.object(self.agent.tun_br, 'delete_port')
) as (ryu_send_msg_fn, del_port_fn):
self.agent.fdb_remove(None, fdb_entry)
del_port_fn.assert_called_once_with(self.tun_name2)
def test_recl_lv_port_to_preserve(self):
self._prepare_l2_pop_ofports()
self.agent.enable_tunneling = True
with mock.patch.object(
self.agent.tun_br, 'cleanup_tunnel_port'
) as clean_tun_fn:
self.agent.reclaim_local_vlan(self.lvms[0].net)
self.assertFalse(clean_tun_fn.called)
def test_recl_lv_port_to_remove(self):
self._prepare_l2_pop_ofports()
self.agent.enable_tunneling = True
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'delete_port'),
mock.patch.object(self.agent, 'ryu_send_msg')
) as (del_port_fn, ryu_send_msg_fn):
self.agent.reclaim_local_vlan(self.lvms[1].net)
del_port_fn.assert_called_once_with(self.tun_name2)
def test_daemon_loop_uses_polling_manager(self):
with mock.patch(
'neutron.agent.linux.polling.get_polling_manager'
@ -671,13 +829,13 @@ class TestOFANeutronAgent(OFAAgentTestCase):
constants.DEFAULT_OVSDBMON_RESPAWN)
mock_loop.assert_called_once_with(polling_manager=fake_pm.__enter__())
def test_setup_tunnel_port_error_negative(self):
def test__setup_tunnel_port_error_negative(self):
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
return_value='-1'),
mock.patch.object(self.mod_agent.LOG, 'error')
) as (add_tunnel_port_fn, log_error_fn):
ofport = self.agent.setup_tunnel_port(
ofport = self.agent._setup_tunnel_port(
'gre-1', 'remote_ip', p_const.TYPE_GRE)
add_tunnel_port_fn.assert_called_once_with(
'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
@ -687,14 +845,14 @@ class TestOFANeutronAgent(OFAAgentTestCase):
{'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
self.assertEqual(ofport, 0)
def test_setup_tunnel_port_error_not_int(self):
def test__setup_tunnel_port_error_not_int(self):
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
return_value=None),
mock.patch.object(self.mod_agent.LOG, 'exception'),
mock.patch.object(self.mod_agent.LOG, 'error')
) as (add_tunnel_port_fn, log_exc_fn, log_error_fn):
ofport = self.agent.setup_tunnel_port(
ofport = self.agent._setup_tunnel_port(
'gre-1', 'remote_ip', p_const.TYPE_GRE)
add_tunnel_port_fn.assert_called_once_with(
'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
@ -707,72 +865,18 @@ class TestOFANeutronAgent(OFAAgentTestCase):
{'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
self.assertEqual(ofport, 0)
def _create_tunnel_port_name(self, tunnel_ip, tunnel_type):
tunnel_ip_hex = '%08x' % netaddr.IPAddress(tunnel_ip, version=4)
return '%s-%s' % (tunnel_type, tunnel_ip_hex)
def test_tunnel_sync_with_valid_ip_address_and_gre_type(self):
tunnel_ip = '100.101.102.103'
self.agent.tunnel_types = ['gre']
tun_name = self._create_tunnel_port_name(tunnel_ip,
self.agent.tunnel_types[0])
fake_tunnel_details = {'tunnels': [{'ip_address': tunnel_ip}]}
with contextlib.nested(
mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
return_value=fake_tunnel_details),
mock.patch.object(self.agent, 'setup_tunnel_port')
) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
self.agent.tunnel_sync()
expected_calls = [mock.call(tun_name, tunnel_ip,
self.agent.tunnel_types[0])]
setup_tunnel_port_fn.assert_has_calls(expected_calls)
def test_tunnel_sync_with_valid_ip_address_and_vxlan_type(self):
tunnel_ip = '100.101.31.15'
def test_tunnel_sync(self):
self.agent.local_ip = 'agent_ip'
self.agent.context = 'fake_context'
self.agent.tunnel_types = ['vxlan']
tun_name = self._create_tunnel_port_name(tunnel_ip,
self.agent.tunnel_types[0])
fake_tunnel_details = {'tunnels': [{'ip_address': tunnel_ip}]}
with contextlib.nested(
mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
return_value=fake_tunnel_details),
mock.patch.object(self.agent, 'setup_tunnel_port')
) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
with mock.patch.object(
self.agent.plugin_rpc, 'tunnel_sync'
) as tunnel_sync_rpc_fn:
self.agent.tunnel_sync()
expected_calls = [mock.call(tun_name, tunnel_ip,
self.agent.tunnel_types[0])]
setup_tunnel_port_fn.assert_has_calls(expected_calls)
def test_tunnel_sync_invalid_ip_address(self):
tunnel_ip = '100.100.100.100'
self.agent.tunnel_types = ['vxlan']
tun_name = self._create_tunnel_port_name(tunnel_ip,
self.agent.tunnel_types[0])
fake_tunnel_details = {'tunnels': [{'ip_address': '300.300.300.300'},
{'ip_address': tunnel_ip}]}
with contextlib.nested(
mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
return_value=fake_tunnel_details),
mock.patch.object(self.agent, 'setup_tunnel_port')
) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
self.agent.tunnel_sync()
setup_tunnel_port_fn.assert_called_once_with(
tun_name, tunnel_ip, self.agent.tunnel_types[0])
def test_tunnel_update(self):
tunnel_ip = '10.10.10.10'
self.agent.tunnel_types = ['gre']
tun_name = self._create_tunnel_port_name(tunnel_ip,
self.agent.tunnel_types[0])
kwargs = {'tunnel_ip': tunnel_ip,
'tunnel_type': self.agent.tunnel_types[0]}
self.agent.setup_tunnel_port = mock.Mock()
self.agent.enable_tunneling = True
self.agent.l2_pop = False
self.agent.tunnel_update(context=None, **kwargs)
expected_calls = [mock.call(tun_name, tunnel_ip,
self.agent.tunnel_types[0])]
self.agent.setup_tunnel_port.assert_has_calls(expected_calls)
tunnel_sync_rpc_fn.assert_called_once_with(
self.agent.context,
self.agent.local_ip,
self.agent.tunnel_types[0])
def test__provision_local_vlan_inbound_for_tunnel(self):
with mock.patch.object(self.agent, 'ryu_send_msg') as sendmsg:

View File

@ -934,7 +934,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
return_value='6'),
mock.patch.object(self.agent.tun_br, "add_flow")
) as (add_tun_port_fn, add_flow_fn):
self.agent.setup_tunnel_port('portname', '1.2.3.4', 'vxlan')
self.agent._setup_tunnel_port('portname', '1.2.3.4', 'vxlan')
self.assertTrue(add_tun_port_fn.called)
def test_port_unbound(self):
@ -978,7 +978,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'add_flow'),
mock.patch.object(self.agent.tun_br, 'delete_flows'),
mock.patch.object(self.agent, 'setup_tunnel_port'),
mock.patch.object(self.agent, '_setup_tunnel_port'),
mock.patch.object(self.agent, 'cleanup_tunnel_port')
) as (add_flow_fn, del_flow_fn, add_tun_fn, clean_tun_fn):
self.agent.fdb_add(None, fdb_entry)
@ -1018,7 +1018,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'add_flow'),
mock.patch.object(self.agent.tun_br, 'mod_flow'),
mock.patch.object(self.agent, 'setup_tunnel_port'),
mock.patch.object(self.agent, '_setup_tunnel_port'),
) as (add_flow_fn, mod_flow_fn, add_tun_fn):
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(add_tun_fn.called)
@ -1088,7 +1088,7 @@ class TestOvsNeutronAgent(base.BaseTestCase):
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'add_flow'),
mock.patch.object(self.agent.tun_br, 'mod_flow'),
mock.patch.object(self.agent, 'setup_tunnel_port')
mock.patch.object(self.agent, '_setup_tunnel_port')
) as (add_flow_fn, mod_flow_fn, add_tun_fn):
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(add_tun_fn.called)
@ -1201,13 +1201,13 @@ class TestOvsNeutronAgent(base.BaseTestCase):
constants.DEFAULT_OVSDBMON_RESPAWN)
mock_loop.assert_called_once_with(polling_manager=mock.ANY)
def test_setup_tunnel_port_error_negative(self):
def test__setup_tunnel_port_error_negative(self):
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
return_value='-1'),
mock.patch.object(ovs_neutron_agent.LOG, 'error')
) as (add_tunnel_port_fn, log_error_fn):
ofport = self.agent.setup_tunnel_port(
ofport = self.agent._setup_tunnel_port(
'gre-1', 'remote_ip', p_const.TYPE_GRE)
add_tunnel_port_fn.assert_called_once_with(
'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
@ -1217,14 +1217,14 @@ class TestOvsNeutronAgent(base.BaseTestCase):
{'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
self.assertEqual(ofport, 0)
def test_setup_tunnel_port_error_not_int(self):
def test__setup_tunnel_port_error_not_int(self):
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
return_value=None),
mock.patch.object(ovs_neutron_agent.LOG, 'exception'),
mock.patch.object(ovs_neutron_agent.LOG, 'error')
) as (add_tunnel_port_fn, log_exc_fn, log_error_fn):
ofport = self.agent.setup_tunnel_port(
ofport = self.agent._setup_tunnel_port(
'gre-1', 'remote_ip', p_const.TYPE_GRE)
add_tunnel_port_fn.assert_called_once_with(
'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
@ -1237,14 +1237,14 @@ class TestOvsNeutronAgent(base.BaseTestCase):
{'type': p_const.TYPE_GRE, 'ip': 'remote_ip'})
self.assertEqual(ofport, 0)
def test_setup_tunnel_port_error_negative_df_disabled(self):
def test__setup_tunnel_port_error_negative_df_disabled(self):
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
return_value='-1'),
mock.patch.object(ovs_neutron_agent.LOG, 'error')
) as (add_tunnel_port_fn, log_error_fn):
self.agent.dont_fragment = False
ofport = self.agent.setup_tunnel_port(
ofport = self.agent._setup_tunnel_port(
'gre-1', 'remote_ip', p_const.TYPE_GRE)
add_tunnel_port_fn.assert_called_once_with(
'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
@ -1260,25 +1260,25 @@ class TestOvsNeutronAgent(base.BaseTestCase):
with contextlib.nested(
mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
return_value=fake_tunnel_details),
mock.patch.object(self.agent, 'setup_tunnel_port')
) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
mock.patch.object(self.agent, '_setup_tunnel_port')
) as (tunnel_sync_rpc_fn, _setup_tunnel_port_fn):
self.agent.tunnel_types = ['gre']
self.agent.tunnel_sync()
expected_calls = [mock.call('gre-42', '100.101.102.103', 'gre')]
setup_tunnel_port_fn.assert_has_calls(expected_calls)
_setup_tunnel_port_fn.assert_has_calls(expected_calls)
def test_tunnel_sync_with_ml2_plugin(self):
fake_tunnel_details = {'tunnels': [{'ip_address': '100.101.31.15'}]}
with contextlib.nested(
mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
return_value=fake_tunnel_details),
mock.patch.object(self.agent, 'setup_tunnel_port')
) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
mock.patch.object(self.agent, '_setup_tunnel_port')
) as (tunnel_sync_rpc_fn, _setup_tunnel_port_fn):
self.agent.tunnel_types = ['vxlan']
self.agent.tunnel_sync()
expected_calls = [mock.call('vxlan-64651f0f',
'100.101.31.15', 'vxlan')]
setup_tunnel_port_fn.assert_has_calls(expected_calls)
_setup_tunnel_port_fn.assert_has_calls(expected_calls)
def test_tunnel_sync_invalid_ip_address(self):
fake_tunnel_details = {'tunnels': [{'ip_address': '300.300.300.300'},
@ -1286,24 +1286,24 @@ class TestOvsNeutronAgent(base.BaseTestCase):
with contextlib.nested(
mock.patch.object(self.agent.plugin_rpc, 'tunnel_sync',
return_value=fake_tunnel_details),
mock.patch.object(self.agent, 'setup_tunnel_port')
) as (tunnel_sync_rpc_fn, setup_tunnel_port_fn):
mock.patch.object(self.agent, '_setup_tunnel_port')
) as (tunnel_sync_rpc_fn, _setup_tunnel_port_fn):
self.agent.tunnel_types = ['vxlan']
self.agent.tunnel_sync()
setup_tunnel_port_fn.assert_called_once_with('vxlan-64646464',
'100.100.100.100',
'vxlan')
_setup_tunnel_port_fn.assert_called_once_with('vxlan-64646464',
'100.100.100.100',
'vxlan')
def test_tunnel_update(self):
kwargs = {'tunnel_ip': '10.10.10.10',
'tunnel_type': 'gre'}
self.agent.setup_tunnel_port = mock.Mock()
self.agent._setup_tunnel_port = mock.Mock()
self.agent.enable_tunneling = True
self.agent.tunnel_types = ['gre']
self.agent.l2_pop = False
self.agent.tunnel_update(context=None, **kwargs)
expected_calls = [mock.call('gre-0a0a0a0a', '10.10.10.10', 'gre')]
self.agent.setup_tunnel_port.assert_has_calls(expected_calls)
self.agent._setup_tunnel_port.assert_has_calls(expected_calls)
def test_ovs_restart(self):
reply2 = {'current': set(['tap0']),