'''
@abc.abstractmethod
- def add_fdb_flow(self, port_info, remote_ip, lvm, ofport):
+ def add_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
'''Add flow for fdb
This method assumes to be used by method fdb_add_tun.
on bridge.
And you may edit some information for local arp respond.
+ :param br: represent the bridge on which add_fdb_flow should be
+ applied.
:param port_info: list to include mac and ip.
+
[mac, ip]
:remote_ip: remote ip address.
:param lvm: a local VLAN map of network.
pass
@abc.abstractmethod
- def del_fdb_flow(self, port_info, remote_ip, lvm, ofport):
+ def del_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
'''Delete flow for fdb
This method assumes to be used by method fdb_remove_tun.
from bridge.
And you may delete some information for local arp respond.
+ :param br: represent the bridge on which del_fdb_flow should be
+ applied.
:param port_info: a list to contain mac and ip.
[mac, ip]
:remote_ip: remote ip address.
pass
@abc.abstractmethod
- def setup_tunnel_port(self, remote_ip, network_type):
+ def setup_tunnel_port(self, br, remote_ip, network_type):
'''Setup an added tunnel port.
This method assumes to be used by method fdb_add_tun.
a port to a bridge.
If you need, you may do some preparation for a bridge.
+ :param br: represent the bridge on which setup_tunnel_port should be
+ applied.
: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):
+ def cleanup_tunnel_port(self, br, tun_ofport, tunnel_type):
'''Clean up a deleted tunnel port.
This method assumes to be used by method fdb_remove_tun.
deleting a port from a bridge.
If you need, you may do some cleanup for a bridge.
+ :param br: represent the bridge on which cleanup_tunnel_port should be
+ applied.
:param tun_ofport: a port value to cleanup.
:param tunnel_type: a type of tunnel.
'''
pass
@abc.abstractmethod
- def setup_entry_for_arp_reply(self, action, local_vid, mac_address,
+ def setup_entry_for_arp_reply(self, br, action, local_vid, mac_address,
ip_address):
'''Operate the ARP respond information.
Do operation of arp respond information for an action
In ovs do adding or removing flow entry to edit an arp reply.
+ :param br: represent the bridge on which setup_entry_for_arp_reply
+ should be applied.
:param action: an action to operate for arp respond infomation.
"add" or "remove"
:param local_vid: id in local VLAN map of network's ARP entry.
yield (lvm, agent_ports)
@log.log
- def fdb_add_tun(self, context, lvm, agent_ports, ofports):
+ def fdb_add_tun(self, context, br, 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)
+ ofport = self.setup_tunnel_port(br, remote_ip,
+ lvm.network_type)
if ofport == 0:
continue
for port in ports:
- self.add_fdb_flow(port, remote_ip, lvm, ofport)
+ self.add_fdb_flow(br, port, remote_ip, lvm, ofport)
@log.log
- def fdb_remove_tun(self, context, lvm, agent_ports, ofports):
+ def fdb_remove_tun(self, context, br, 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)
+ self.del_fdb_flow(br, 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)
+ self.cleanup_tunnel_port(br, ofport, lvm.network_type)
@log.log
def fdb_update(self, context, fdb_entries):
getattr(self, method)(context, values)
@log.log
- def fdb_chg_ip_tun(self, context, fdb_entries, local_ip, local_vlan_map):
+ def fdb_chg_ip_tun(self, context, br, fdb_entries, local_ip,
+ local_vlan_map):
'''fdb update when an IP of a port is updated.
The ML2 l2-pop mechanism driver sends an fdb update rpc message when an
IP of a port is updated.
:param context: RPC context.
+ :param br: represent the bridge on which fdb_chg_ip_tun should be
+ applied.
:param fdb_entries: fdb dicts that contain all mac/IP informations per
agent and network.
{'net1':
after = state.get('after')
for mac, ip in after:
- self.setup_entry_for_arp_reply('add', lvm.vlan, mac, ip)
+ self.setup_entry_for_arp_reply(br, 'add', lvm.vlan, mac,
+ ip)
before = state.get('before')
for mac, ip in before:
- self.setup_entry_for_arp_reply('remove', lvm.vlan, mac, ip)
+ self.setup_entry_for_arp_reply(br, 'remove', lvm.vlan, mac,
+ ip)
# License for the specific language governing permissions and limitations
# under the License.
+import itertools
+import operator
+
from oslo.config import cfg
from neutron.agent.linux import ip_lib
def __init__(self, br_name, root_helper):
super(OVSBridge, self).__init__(root_helper)
self.br_name = br_name
- self.defer_apply_flows = False
- self.deferred_flows = {'add': '', 'mod': '', 'del': ''}
def set_controller(self, controller_names):
vsctl_command = ['--', 'set-controller', self.br_name]
return self.db_get_val('Bridge',
self.br_name, 'datapath_id').strip('"')
+ def do_action_flows(self, action, kwargs_list):
+ flow_strs = [_build_flow_expr_str(kw, action) for kw in kwargs_list]
+ self.run_ofctl('%s-flows' % action, ['-'], '\n'.join(flow_strs))
+
def add_flow(self, **kwargs):
- flow_str = _build_flow_expr_str(kwargs, 'add')
- if self.defer_apply_flows:
- self.deferred_flows['add'] += flow_str + '\n'
- else:
- self.run_ofctl("add-flow", [flow_str])
+ self.do_action_flows('add', [kwargs])
def mod_flow(self, **kwargs):
- flow_str = _build_flow_expr_str(kwargs, 'mod')
- if self.defer_apply_flows:
- self.deferred_flows['mod'] += flow_str + '\n'
- else:
- self.run_ofctl("mod-flows", [flow_str])
+ self.do_action_flows('mod', [kwargs])
def delete_flows(self, **kwargs):
- flow_expr_str = _build_flow_expr_str(kwargs, 'del')
- if self.defer_apply_flows:
- self.deferred_flows['del'] += flow_expr_str + '\n'
- else:
- self.run_ofctl("del-flows", [flow_expr_str])
+ self.do_action_flows('del', [kwargs])
def dump_flows_for_table(self, table):
retval = None
if 'NXST' not in item)
return retval
- def defer_apply_on(self):
- # TODO(vivek): when defer_apply_on is used, DVR
- # flows are only getting partially configured when
- # run concurrently with l2-pop ON.
- # Will need make ovs_lib flow API context sensitive
- # and then use the same across this file, which will
- # address the race issue here.
- LOG.debug(_('defer_apply_on'))
- self.defer_apply_flows = True
-
- def defer_apply_off(self):
- # TODO(vivek): when defer_apply_off is used, DVR
- # flows are only getting partially configured when
- # run concurrently with l2-pop ON.
- # Will need make ovs_lib flow API context sensitive
- # and then use the same across this file, which will
- # address the race issue here.
- LOG.debug(_('defer_apply_off'))
- # Note(ethuleau): stash flows and disable deferred mode. Then apply
- # flows from the stashed reference to be sure to not purge flows that
- # were added between two ofctl commands.
- stashed_deferred_flows, self.deferred_flows = (
- self.deferred_flows, {'add': '', 'mod': '', 'del': ''}
- )
- self.defer_apply_flows = False
- for action, flows in stashed_deferred_flows.items():
- if flows:
- LOG.debug(_('Applying following deferred flows '
- 'to bridge %s'), self.br_name)
- for line in flows.splitlines():
- LOG.debug(_('%(action)s: %(flow)s'),
- {'action': action, 'flow': line})
- self.run_ofctl('%s-flows' % action, ['-'], flows)
+ def deferred(self, **kwargs):
+ return DeferredOVSBridge(self, **kwargs)
def add_tunnel_port(self, port_name, remote_ip, local_ip,
tunnel_type=p_const.TYPE_GRE,
self.destroy()
+class DeferredOVSBridge(object):
+ '''Deferred OVSBridge.
+
+ This class wraps add_flow, mod_flow and delete_flows calls to an OVSBridge
+ and defers their application until apply_flows call in order to perform
+ bulk calls. It wraps also ALLOWED_PASSTHROUGHS calls to avoid mixing
+ OVSBridge and DeferredOVSBridge uses.
+ This class can be used as a context, in such case apply_flows is called on
+ __exit__ except if an exception is raised.
+ This class is not thread-safe, that's why for every use a new instance
+ must be implemented.
+ '''
+ ALLOWED_PASSTHROUGHS = 'add_port', 'delete_port'
+
+ def __init__(self, br, full_ordered=False,
+ order=('add', 'mod', 'del')):
+ '''Constructor.
+
+ :param br: wrapped bridge
+ :param full_ordered: Optional, disable flow reordering (slower)
+ :param order: Optional, define in which order flow are applied
+ '''
+
+ self.br = br
+ self.full_ordered = full_ordered
+ self.order = order
+ if not self.full_ordered:
+ self.weights = dict((y, x) for x, y in enumerate(self.order))
+ self.action_flow_tuples = []
+
+ def __getattr__(self, name):
+ if name in self.ALLOWED_PASSTHROUGHS:
+ return getattr(self.br, name)
+ raise AttributeError(name)
+
+ def add_flow(self, **kwargs):
+ self.action_flow_tuples.append(('add', kwargs))
+
+ def mod_flow(self, **kwargs):
+ self.action_flow_tuples.append(('mod', kwargs))
+
+ def delete_flows(self, **kwargs):
+ self.action_flow_tuples.append(('del', kwargs))
+
+ def apply_flows(self):
+ action_flow_tuples = self.action_flow_tuples
+ self.action_flow_tuples = []
+ if not action_flow_tuples:
+ return
+
+ if not self.full_ordered:
+ action_flow_tuples.sort(key=lambda af: self.weights[af[0]])
+
+ grouped = itertools.groupby(action_flow_tuples,
+ key=operator.itemgetter(0))
+ itemgetter_1 = operator.itemgetter(1)
+ for action, action_flow_list in grouped:
+ flows = map(itemgetter_1, action_flow_list)
+ self.br.do_action_flows(action, flows)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ if exc_type is None:
+ self.apply_flows()
+ else:
+ LOG.exception(_("OVS flows could not be applied on bridge %s"),
+ self.br.br_name)
+
+
def get_bridge_for_iface(root_helper, iface):
args = ["ovs-vsctl", "--timeout=%d" % cfg.CONF.ovs_vsctl_timeout,
"iface-to-br", iface]
self.local_vlan_map):
agent_ports.pop(self.local_ip, None)
if len(agent_ports):
- self.fdb_add_tun(context, lvm, agent_ports,
+ self.fdb_add_tun(context, self.tun_br, lvm, agent_ports,
self.tun_br_ofports)
def fdb_remove(self, context, 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.fdb_remove_tun(context, self.tun_br, lvm, agent_ports,
self.tun_br_ofports)
- def _add_fdb_flooding_flow(self, lvm):
- datapath = self.tun_br.datapath
+ def _add_fdb_flooding_flow(self, br, lvm):
+ datapath = br.datapath
ofp = datapath.ofproto
ofpp = datapath.ofproto_parser
match = ofpp.OFPMatch(
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
+ def add_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
+ datapath = 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)
+ self._add_fdb_flooding_flow(br, lvm)
else:
self.ryuapp.add_arp_table_entry(
lvm.vlan, port_info[1], port_info[0])
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
+ def del_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
+ datapath = 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)
+ self._add_fdb_flooding_flow(br, lvm)
else:
# This local vlan doesn't require any more tunelling
match = ofpp.OFPMatch(
match=match)
self.ryu_send_msg(msg)
- def setup_entry_for_arp_reply(self, action, local_vid, mac_address,
+ def setup_entry_for_arp_reply(self, br, action, local_vid, mac_address,
ip_address):
if action == 'add':
self.ryuapp.add_arp_table_entry(local_vid, ip_address, mac_address)
def _fdb_chg_ip(self, context, fdb_entries):
LOG.debug("update chg_ip received")
- self.fdb_chg_ip_tun(
- context, fdb_entries, self.local_ip, self.local_vlan_map)
+ self.fdb_chg_ip_tun(context, self.tun_br, fdb_entries, self.local_ip,
+ self.local_vlan_map)
def _provision_local_vlan_inbound_for_tunnel(self, lvid, network_type,
segmentation_id):
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)
+ self.cleanup_tunnel_port(self.tun_br, 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)
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):
- ofport = self.tun_br.add_tunnel_port(port_name,
- remote_ip,
- self.local_ip,
- tunnel_type,
- self.vxlan_udp_port,
- self.dont_fragment)
+ def _setup_tunnel_port(self, br, port_name, remote_ip, tunnel_type):
+ ofport = br.add_tunnel_port(port_name,
+ remote_ip,
+ self.local_ip,
+ tunnel_type,
+ self.vxlan_udp_port,
+ self.dont_fragment)
ofport_int = -1
try:
ofport_int = int(ofport)
self.tun_br_ofports[tunnel_type][remote_ip] = ofport
# Add flow in default table to resubmit to the right
# tunelling table (lvid will be set in the latter)
- match = self.tun_br.ofparser.OFPMatch(in_port=int(ofport))
- instructions = [self.tun_br.ofparser.OFPInstructionGotoTable(
+ match = br.ofparser.OFPMatch(in_port=int(ofport))
+ instructions = [br.ofparser.OFPInstructionGotoTable(
table_id=constants.TUN_TABLE[tunnel_type])]
- msg = self.tun_br.ofparser.OFPFlowMod(self.tun_br.datapath,
- priority=1,
- match=match,
- instructions=instructions)
+ msg = br.ofparser.OFPFlowMod(br.datapath,
+ priority=1,
+ match=match,
+ instructions=instructions)
self.ryu_send_msg(msg)
return ofport
- def setup_tunnel_port(self, remote_ip, network_type):
+ def setup_tunnel_port(self, br, 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,
+ ofport = self._setup_tunnel_port(br,
+ port_name,
remote_ip,
network_type)
return ofport
- def _remove_tunnel_port(self, tun_ofport, tunnel_type):
- datapath = self.tun_br.datapath
+ def _remove_tunnel_port(self, br, tun_ofport, tunnel_type):
+ datapath = br.datapath
ofp = datapath.ofproto
ofpp = datapath.ofproto_parser
for remote_ip, ofport in self.tun_br_ofports[tunnel_type].items():
port_name = self._create_tunnel_port_name(tunnel_type,
remote_ip)
if port_name:
- self.tun_br.delete_port(port_name)
+ br.delete_port(port_name)
match = ofpp.OFPMatch(in_port=int(ofport))
msg = ofpp.OFPFlowMod(datapath,
command=ofp.OFPFC_DELETE,
self.ryu_send_msg(msg)
self.tun_br_ofports[tunnel_type].pop(remote_ip, None)
- def cleanup_tunnel_port(self, tun_ofport, tunnel_type):
+ def cleanup_tunnel_port(self, br, 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)
+ self._remove_tunnel_port(br, tun_ofport, tunnel_type)
def treat_devices_added_or_updated(self, devices):
resync = False
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(self.tun_br, tun_name, tunnel_ip,
+ tunnel_type)
def fdb_add(self, context, fdb_entries):
LOG.debug("fdb_add received")
agent_ports.pop(self.local_ip, None)
if len(agent_ports):
if not self.enable_distributed_routing:
- self.tun_br.defer_apply_on()
- self.fdb_add_tun(context, lvm, agent_ports,
- self.tun_br_ofports)
- if not self.enable_distributed_routing:
- self.tun_br.defer_apply_off()
+ with self.tun_br.deferred() as deferred_br:
+ self.fdb_add_tun(context, deferred_br, lvm,
+ agent_ports, self.tun_br_ofports)
+ else:
+ self.fdb_add_tun(context, self.tun_br, lvm,
+ agent_ports, self.tun_br_ofports)
def fdb_remove(self, context, fdb_entries):
LOG.debug("fdb_remove received")
agent_ports.pop(self.local_ip, None)
if len(agent_ports):
if not self.enable_distributed_routing:
- self.tun_br.defer_apply_on()
- self.fdb_remove_tun(context, lvm, agent_ports,
- self.tun_br_ofports)
- if not self.enable_distributed_routing:
- self.tun_br.defer_apply_off()
+ with self.tun_br.deferred() as deferred_br:
+ self.fdb_remove_tun(context, deferred_br, lvm,
+ agent_ports, self.tun_br_ofports)
+ else:
+ self.fdb_remove_tun(context, self.tun_br, lvm,
+ agent_ports, self.tun_br_ofports)
- def add_fdb_flow(self, port_info, remote_ip, lvm, ofport):
+ def add_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
if port_info == q_const.FLOODING_ENTRY:
lvm.tun_ofports.add(ofport)
ofports = ','.join(lvm.tun_ofports)
- self.tun_br.mod_flow(table=constants.FLOOD_TO_TUN,
- dl_vlan=lvm.vlan,
- actions="strip_vlan,set_tunnel:%s,"
- "output:%s" % (lvm.segmentation_id, ofports))
+ br.mod_flow(table=constants.FLOOD_TO_TUN,
+ dl_vlan=lvm.vlan,
+ actions="strip_vlan,set_tunnel:%s,output:%s" %
+ (lvm.segmentation_id, ofports))
else:
- self.setup_entry_for_arp_reply('add', lvm.vlan, port_info[0],
+ self.setup_entry_for_arp_reply(br, 'add', lvm.vlan, port_info[0],
port_info[1])
if not self.dvr_agent.is_dvr_router_interface(port_info[1]):
- self.tun_br.add_flow(table=constants.UCAST_TO_TUN,
- priority=2,
- dl_vlan=lvm.vlan,
- dl_dst=port_info[0],
- actions="strip_vlan,set_tunnel:%s,"
- "output:%s" %
- (lvm.segmentation_id, ofport))
-
- def del_fdb_flow(self, port_info, remote_ip, lvm, ofport):
+ br.add_flow(table=constants.UCAST_TO_TUN,
+ priority=2,
+ dl_vlan=lvm.vlan,
+ dl_dst=port_info[0],
+ actions="strip_vlan,set_tunnel:%s,output:%s" %
+ (lvm.segmentation_id, ofport))
+
+ def del_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
if port_info == q_const.FLOODING_ENTRY:
lvm.tun_ofports.remove(ofport)
if len(lvm.tun_ofports) > 0:
ofports = ','.join(lvm.tun_ofports)
- self.tun_br.mod_flow(table=constants.FLOOD_TO_TUN,
- dl_vlan=lvm.vlan,
- actions="strip_vlan,"
- "set_tunnel:%s,output:%s" %
- (lvm.segmentation_id, ofports))
+ br.mod_flow(table=constants.FLOOD_TO_TUN,
+ dl_vlan=lvm.vlan,
+ actions="strip_vlan,set_tunnel:%s,output:%s" %
+ (lvm.segmentation_id, ofports))
else:
# This local vlan doesn't require any more tunnelling
- self.tun_br.delete_flows(table=constants.FLOOD_TO_TUN,
- dl_vlan=lvm.vlan)
+ br.delete_flows(table=constants.FLOOD_TO_TUN, dl_vlan=lvm.vlan)
else:
- self.setup_entry_for_arp_reply('remove', lvm.vlan, port_info[0],
- port_info[1])
- self.tun_br.delete_flows(table=constants.UCAST_TO_TUN,
- dl_vlan=lvm.vlan,
- dl_dst=port_info[0])
+ self.setup_entry_for_arp_reply(br, 'remove', lvm.vlan,
+ port_info[0], port_info[1])
+ br.delete_flows(table=constants.UCAST_TO_TUN,
+ dl_vlan=lvm.vlan,
+ dl_dst=port_info[0])
def _fdb_chg_ip(self, context, fdb_entries):
LOG.debug("update chg_ip received")
- self.fdb_chg_ip_tun(
- context, fdb_entries, self.local_ip, self.local_vlan_map)
+ with self.tun_br.deferred() as deferred_br:
+ self.fdb_chg_ip_tun(context, deferred_br, fdb_entries,
+ self.local_ip, self.local_vlan_map)
- def setup_entry_for_arp_reply(self, action, local_vid, mac_address,
+ def setup_entry_for_arp_reply(self, br, action, local_vid, mac_address,
ip_address):
'''Set the ARP respond entry.
if action == 'add':
actions = constants.ARP_RESPONDER_ACTIONS % {'mac': mac, 'ip': ip}
- self.tun_br.add_flow(table=constants.ARP_RESPONDER,
- priority=1,
- proto='arp',
- dl_vlan=local_vid,
- nw_dst='%s' % ip,
- actions=actions)
+ br.add_flow(table=constants.ARP_RESPONDER,
+ priority=1,
+ proto='arp',
+ dl_vlan=local_vid,
+ nw_dst='%s' % ip,
+ actions=actions)
elif action == 'remove':
- self.tun_br.delete_flows(table=constants.ARP_RESPONDER,
- proto='arp',
- dl_vlan=local_vid,
- nw_dst='%s' % ip)
+ br.delete_flows(table=constants.ARP_RESPONDER,
+ proto='arp',
+ dl_vlan=local_vid,
+ nw_dst='%s' % ip)
else:
LOG.warning(_('Action %s not supported'), action)
if self.l2_pop:
# 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)
+ self.cleanup_tunnel_port(self.tun_br, ofport,
+ lvm.network_type)
elif lvm.network_type == p_const.TYPE_FLAT:
if lvm.physical_network in self.phys_brs:
# outbound
ancillary_bridges.append(br)
return ancillary_bridges
- def setup_tunnel_br(self, tun_br=None):
+ def setup_tunnel_br(self, tun_br_name=None):
'''Setup the tunnel bridge.
Creates tunnel bridge, and links it to the integration bridge
using a patch port.
- :param tun_br: the name of the tunnel bridge.
+ :param tun_br_name: the name of the tunnel bridge.
'''
if not self.tun_br:
- self.tun_br = ovs_lib.OVSBridge(tun_br, self.root_helper)
+ self.tun_br = ovs_lib.OVSBridge(tun_br_name, self.root_helper)
self.tun_br.reset_bridge()
self.patch_tun_ofport = self.int_br.add_patch_port(
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):
- ofport = self.tun_br.add_tunnel_port(port_name,
- remote_ip,
- self.local_ip,
- tunnel_type,
- self.vxlan_udp_port,
- self.dont_fragment)
+ def _setup_tunnel_port(self, br, port_name, remote_ip, tunnel_type):
+ ofport = br.add_tunnel_port(port_name,
+ remote_ip,
+ self.local_ip,
+ tunnel_type,
+ self.vxlan_udp_port,
+ self.dont_fragment)
ofport_int = -1
try:
ofport_int = int(ofport)
self.tun_br_ofports[tunnel_type][remote_ip] = ofport
# Add flow in default table to resubmit to the right
# tunnelling table (lvid will be set in the latter)
- self.tun_br.add_flow(priority=1,
- in_port=ofport,
- actions="resubmit(,%s)" %
- constants.TUN_TABLE[tunnel_type])
+ br.add_flow(priority=1,
+ in_port=ofport,
+ actions="resubmit(,%s)" %
+ constants.TUN_TABLE[tunnel_type])
ofports = ','.join(self.tun_br_ofports[tunnel_type].values())
if ofports and not self.l2_pop:
# 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:
- self.tun_br.mod_flow(table=constants.FLOOD_TO_TUN,
- dl_vlan=vlan_mapping.vlan,
- actions="strip_vlan,"
- "set_tunnel:%s,output:%s" %
- (vlan_mapping.segmentation_id,
- ofports))
+ br.mod_flow(table=constants.FLOOD_TO_TUN,
+ dl_vlan=vlan_mapping.vlan,
+ actions="strip_vlan,set_tunnel:%s,output:%s" %
+ (vlan_mapping.segmentation_id, ofports))
return ofport
- def setup_tunnel_port(self, remote_ip, network_type):
+ def setup_tunnel_port(self, br, 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,
+ ofport = self._setup_tunnel_port(br,
+ port_name,
remote_ip,
network_type)
return ofport
- def cleanup_tunnel_port(self, tun_ofport, tunnel_type):
+ def cleanup_tunnel_port(self, br, 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:
if ofport == tun_ofport:
port_name = '%s-%s' % (tunnel_type,
self.get_ip_in_hex(remote_ip))
- self.tun_br.delete_port(port_name)
- self.tun_br.delete_flows(in_port=ofport)
+ br.delete_port(port_name)
+ br.delete_flows(in_port=ofport)
self.tun_br_ofports[tunnel_type].pop(remote_ip, None)
def treat_devices_added_or_updated(self, devices, ovs_restarted):
return
def tunnel_sync(self):
- resync = False
try:
for tunnel_type in self.tunnel_types:
details = self.plugin_rpc.tunnel_sync(self.context,
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(self.tun_br,
+ 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})
- resync = True
- return resync
+ return True
+ return False
def _agent_has_updates(self, polling_manager):
return (polling_manager.is_polling_required or
# @author: Fumihiko Kakuma, VA Linux Systems Japan K.K.
import collections
+import mock
from neutron.agent import l2population_rpc
from neutron.plugins.openvswitch.agent import ovs_neutron_agent
def fdb_remove(self, context, fdb_entries):
pass
- def add_fdb_flow(self, port_info, remote_ip, lvm, ofport):
+ def add_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
pass
- def del_fdb_flow(self, port_info, remote_ip, lvm, ofport):
+ def del_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
pass
- def setup_tunnel_port(self, remote_ip, network_type):
+ def setup_tunnel_port(self, br, remote_ip, network_type):
pass
- def cleanup_tunnel_port(self, tun_ofport, tunnel_type):
+ def cleanup_tunnel_port(self, br, tun_ofport, tunnel_type):
pass
- def setup_entry_for_arp_reply(self, action, local_vid, mac_address,
+ def setup_entry_for_arp_reply(self, br, action, local_vid, mac_address,
ip_address):
pass
def setUp(self):
super(TestL2populationRpcCallBackTunnelMixinBase, self).setUp()
self.fakeagent = FakeNeutronAgent()
+ self.fakebr = mock.Mock()
Port = collections.namedtuple('Port', 'ip, ofport')
LVM = collections.namedtuple(
'LVM', 'net, vlan, phys, segid, mac, ip, vif, port')
self.br.add_flow(**flow_dict_6)
self.br.add_flow(**flow_dict_7)
expected_calls = [
- mock.call(["ovs-ofctl", "add-flow", self.BR_NAME,
- "hard_timeout=0,idle_timeout=0,"
- "priority=2,dl_src=ca:fe:de:ad:be:ef"
- ",actions=strip_vlan,output:0"],
- process_input=None, root_helper=self.root_helper),
- mock.call(["ovs-ofctl", "add-flow", self.BR_NAME,
- "hard_timeout=0,idle_timeout=0,"
- "priority=1,actions=normal"],
- process_input=None, root_helper=self.root_helper),
- mock.call(["ovs-ofctl", "add-flow", self.BR_NAME,
- "hard_timeout=0,idle_timeout=0,"
- "priority=2,actions=drop"],
- process_input=None, root_helper=self.root_helper),
- mock.call(["ovs-ofctl", "add-flow", self.BR_NAME,
- "hard_timeout=0,idle_timeout=0,"
- "priority=2,in_port=%s,actions=drop" % ofport],
- process_input=None, root_helper=self.root_helper),
- mock.call(["ovs-ofctl", "add-flow", self.BR_NAME,
- "hard_timeout=0,idle_timeout=0,"
- "priority=4,dl_vlan=%s,in_port=%s,"
- "actions=strip_vlan,set_tunnel:%s,normal"
- % (vid, ofport, lsw_id)],
- process_input=None, root_helper=self.root_helper),
- mock.call(["ovs-ofctl", "add-flow", self.BR_NAME,
- "hard_timeout=0,idle_timeout=0,"
- "priority=3,tun_id=%s,actions="
- "mod_vlan_vid:%s,output:%s"
- % (lsw_id, vid, ofport)],
- process_input=None, root_helper=self.root_helper),
- mock.call(["ovs-ofctl", "add-flow", self.BR_NAME,
- "hard_timeout=0,idle_timeout=0,"
- "priority=4,nw_src=%s,arp,actions=drop" % cidr],
- process_input=None, root_helper=self.root_helper),
+ mock.call(["ovs-ofctl", "add-flows", self.BR_NAME, '-'],
+ process_input="hard_timeout=0,idle_timeout=0,"
+ "priority=2,dl_src=ca:fe:de:ad:be:ef"
+ ",actions=strip_vlan,output:0",
+ root_helper=self.root_helper),
+ mock.call(["ovs-ofctl", "add-flows", self.BR_NAME, '-'],
+ process_input="hard_timeout=0,idle_timeout=0,"
+ "priority=1,actions=normal",
+ root_helper=self.root_helper),
+ mock.call(["ovs-ofctl", "add-flows", self.BR_NAME, '-'],
+ process_input="hard_timeout=0,idle_timeout=0,"
+ "priority=2,actions=drop",
+ root_helper=self.root_helper),
+ mock.call(["ovs-ofctl", "add-flows", self.BR_NAME, '-'],
+ process_input="hard_timeout=0,idle_timeout=0,priority=2,"
+ "in_port=%s,actions=drop" % ofport,
+ root_helper=self.root_helper),
+ mock.call(["ovs-ofctl", "add-flows", self.BR_NAME, '-'],
+ process_input="hard_timeout=0,idle_timeout=0,"
+ "priority=4,dl_vlan=%s,in_port=%s,"
+ "actions=strip_vlan,set_tunnel:%s,normal"
+ % (vid, ofport, lsw_id),
+ root_helper=self.root_helper),
+ mock.call(["ovs-ofctl", "add-flows", self.BR_NAME, '-'],
+ process_input="hard_timeout=0,idle_timeout=0,priority=3,"
+ "tun_id=%s,actions=mod_vlan_vid:%s,"
+ "output:%s" % (lsw_id, vid, ofport),
+ root_helper=self.root_helper),
+ mock.call(["ovs-ofctl", "add-flows", self.BR_NAME, '-'],
+ process_input="hard_timeout=0,idle_timeout=0,priority=4,"
+ "nw_src=%s,arp,actions=drop" % cidr,
+ root_helper=self.root_helper),
]
self.execute.assert_has_calls(expected_calls)
self.br.add_flow(**flow_dict)
self.execute.assert_called_once_with(
- ["ovs-ofctl", "add-flow", self.BR_NAME,
- "hard_timeout=1000,idle_timeout=2000,priority=1,actions=normal"],
- process_input=None,
+ ["ovs-ofctl", "add-flows", self.BR_NAME, '-'],
+ process_input="hard_timeout=1000,idle_timeout=2000,priority=1,"
+ "actions=normal",
root_helper=self.root_helper)
def test_add_flow_default_priority(self):
self.br.add_flow(**flow_dict)
self.execute.assert_called_once_with(
- ["ovs-ofctl", "add-flow", self.BR_NAME,
- "hard_timeout=0,idle_timeout=0,priority=1,actions=normal"],
- process_input=None,
+ ["ovs-ofctl", "add-flows", self.BR_NAME, '-'],
+ process_input="hard_timeout=0,idle_timeout=0,priority=1,"
+ "actions=normal",
root_helper=self.root_helper)
def _test_get_port_ofport(self, ofport, expected_result):
self.br.delete_flows(tun_id=lsw_id)
self.br.delete_flows(dl_vlan=vid)
expected_calls = [
- mock.call(["ovs-ofctl", "del-flows", self.BR_NAME,
- "in_port=" + ofport],
- process_input=None, root_helper=self.root_helper),
- mock.call(["ovs-ofctl", "del-flows", self.BR_NAME,
- "tun_id=%s" % lsw_id],
- process_input=None, root_helper=self.root_helper),
- mock.call(["ovs-ofctl", "del-flows", self.BR_NAME,
- "dl_vlan=%s" % vid],
- process_input=None, root_helper=self.root_helper),
+ mock.call(["ovs-ofctl", "del-flows", self.BR_NAME, '-'],
+ process_input="in_port=" + ofport,
+ root_helper=self.root_helper),
+ mock.call(["ovs-ofctl", "del-flows", self.BR_NAME, '-'],
+ process_input="tun_id=%s" % lsw_id,
+ root_helper=self.root_helper),
+ mock.call(["ovs-ofctl", "del-flows", self.BR_NAME, '-'],
+ process_input="dl_vlan=%s" % vid,
+ root_helper=self.root_helper),
]
self.execute.assert_has_calls(expected_calls)
self.br.mod_flow,
**params)
- def test_defer_apply_flows(self):
-
- flow_expr = mock.patch.object(ovs_lib, '_build_flow_expr_str').start()
- flow_expr.side_effect = ['added_flow_1', 'added_flow_2',
- 'deleted_flow_1']
- run_ofctl = mock.patch.object(self.br, 'run_ofctl').start()
-
- self.br.defer_apply_on()
- self.br.add_flow(flow='add_flow_1')
- self.br.defer_apply_on()
- self.br.add_flow(flow='add_flow_2')
- self.br.delete_flows(flow='delete_flow_1')
- self.br.defer_apply_off()
-
- flow_expr.assert_has_calls([
- mock.call({'flow': 'add_flow_1'}, 'add'),
- mock.call({'flow': 'add_flow_2'}, 'add'),
- mock.call({'flow': 'delete_flow_1'}, 'del')
- ])
-
- run_ofctl.assert_has_calls([
- mock.call('add-flows', ['-'], 'added_flow_1\nadded_flow_2\n'),
- mock.call('del-flows', ['-'], 'deleted_flow_1\n')
- ])
-
- def test_defer_apply_flows_concurrently(self):
- flow_expr = mock.patch.object(ovs_lib, '_build_flow_expr_str').start()
- flow_expr.side_effect = ['added_flow_1', 'deleted_flow_1',
- 'modified_flow_1', 'added_flow_2',
- 'deleted_flow_2', 'modified_flow_2']
-
- run_ofctl = mock.patch.object(self.br, 'run_ofctl').start()
-
- def run_ofctl_fake(cmd, args, process_input=None):
- self.br.defer_apply_on()
- if cmd == 'add-flows':
- self.br.add_flow(flow='added_flow_2')
- elif cmd == 'del-flows':
- self.br.delete_flows(flow='deleted_flow_2')
- elif cmd == 'mod-flows':
- self.br.mod_flow(flow='modified_flow_2')
- run_ofctl.side_effect = run_ofctl_fake
-
- self.br.defer_apply_on()
- self.br.add_flow(flow='added_flow_1')
- self.br.delete_flows(flow='deleted_flow_1')
- self.br.mod_flow(flow='modified_flow_1')
- self.br.defer_apply_off()
-
- run_ofctl.side_effect = None
- self.br.defer_apply_off()
-
- flow_expr.assert_has_calls([
- mock.call({'flow': 'added_flow_1'}, 'add'),
- mock.call({'flow': 'deleted_flow_1'}, 'del'),
- mock.call({'flow': 'modified_flow_1'}, 'mod'),
- mock.call({'flow': 'added_flow_2'}, 'add'),
- mock.call({'flow': 'deleted_flow_2'}, 'del'),
- mock.call({'flow': 'modified_flow_2'}, 'mod')
- ])
- run_ofctl.assert_has_calls([
- mock.call('add-flows', ['-'], 'added_flow_1\n'),
- mock.call('del-flows', ['-'], 'deleted_flow_1\n'),
- mock.call('mod-flows', ['-'], 'modified_flow_1\n'),
- mock.call('add-flows', ['-'], 'added_flow_2\n'),
- mock.call('del-flows', ['-'], 'deleted_flow_2\n'),
- mock.call('mod-flows', ['-'], 'modified_flow_2\n')
- ])
-
def test_add_tunnel_port(self):
pname = "tap99"
local_ip = "1.1.1.1"
data = [[["map", external_ids], "tap99", 1]]
self.assertIsNone(self._test_get_vif_port_by_id('tap99id', data,
"br-ext"))
+
+
+class TestDeferredOVSBridge(base.BaseTestCase):
+
+ def setUp(self):
+ super(TestDeferredOVSBridge, self).setUp()
+
+ self.br = mock.Mock()
+ self.mocked_do_action_flows = mock.patch.object(
+ self.br, 'do_action_flows').start()
+
+ self.add_flow_dict1 = dict(in_port=11, actions='drop')
+ self.add_flow_dict2 = dict(in_port=12, actions='drop')
+ self.mod_flow_dict1 = dict(in_port=21, actions='drop')
+ self.mod_flow_dict2 = dict(in_port=22, actions='drop')
+ self.del_flow_dict1 = dict(in_port=31)
+ self.del_flow_dict2 = dict(in_port=32)
+
+ def _verify_mock_call(self, expected_calls):
+ self.mocked_do_action_flows.assert_has_calls(expected_calls)
+ self.assertEqual(len(expected_calls),
+ len(self.mocked_do_action_flows.mock_calls))
+
+ def test_apply_on_exit(self):
+ expected_calls = [
+ mock.call('add', [self.add_flow_dict1]),
+ mock.call('mod', [self.mod_flow_dict1]),
+ mock.call('del', [self.del_flow_dict1]),
+ ]
+
+ with ovs_lib.DeferredOVSBridge(self.br) as deferred_br:
+ deferred_br.add_flow(**self.add_flow_dict1)
+ deferred_br.mod_flow(**self.mod_flow_dict1)
+ deferred_br.delete_flows(**self.del_flow_dict1)
+ self._verify_mock_call([])
+ self._verify_mock_call(expected_calls)
+
+ def test_apply_on_exit_with_errors(self):
+ try:
+ with ovs_lib.DeferredOVSBridge(self.br) as deferred_br:
+ deferred_br.add_flow(**self.add_flow_dict1)
+ deferred_br.mod_flow(**self.mod_flow_dict1)
+ deferred_br.delete_flows(**self.del_flow_dict1)
+ raise Exception
+ except Exception:
+ self._verify_mock_call([])
+ else:
+ self.fail('Exception would be reraised')
+
+ def test_apply(self):
+ expected_calls = [
+ mock.call('add', [self.add_flow_dict1]),
+ mock.call('mod', [self.mod_flow_dict1]),
+ mock.call('del', [self.del_flow_dict1]),
+ ]
+
+ with ovs_lib.DeferredOVSBridge(self.br) as deferred_br:
+ deferred_br.add_flow(**self.add_flow_dict1)
+ deferred_br.mod_flow(**self.mod_flow_dict1)
+ deferred_br.delete_flows(**self.del_flow_dict1)
+ self._verify_mock_call([])
+ deferred_br.apply_flows()
+ self._verify_mock_call(expected_calls)
+ self._verify_mock_call(expected_calls)
+
+ def test_apply_order(self):
+ expected_calls = [
+ mock.call('del', [self.del_flow_dict1, self.del_flow_dict2]),
+ mock.call('mod', [self.mod_flow_dict1, self.mod_flow_dict2]),
+ mock.call('add', [self.add_flow_dict1, self.add_flow_dict2]),
+ ]
+
+ order = 'del', 'mod', 'add'
+ with ovs_lib.DeferredOVSBridge(self.br, order=order) as deferred_br:
+ deferred_br.add_flow(**self.add_flow_dict1)
+ deferred_br.mod_flow(**self.mod_flow_dict1)
+ deferred_br.delete_flows(**self.del_flow_dict1)
+ deferred_br.delete_flows(**self.del_flow_dict2)
+ deferred_br.add_flow(**self.add_flow_dict2)
+ deferred_br.mod_flow(**self.mod_flow_dict2)
+ self._verify_mock_call(expected_calls)
+
+ def test_apply_full_ordered(self):
+ expected_calls = [
+ mock.call('add', [self.add_flow_dict1]),
+ mock.call('mod', [self.mod_flow_dict1]),
+ mock.call('del', [self.del_flow_dict1, self.del_flow_dict2]),
+ mock.call('add', [self.add_flow_dict2]),
+ mock.call('mod', [self.mod_flow_dict2]),
+ ]
+
+ with ovs_lib.DeferredOVSBridge(self.br,
+ full_ordered=True) as deferred_br:
+ deferred_br.add_flow(**self.add_flow_dict1)
+ deferred_br.mod_flow(**self.mod_flow_dict1)
+ deferred_br.delete_flows(**self.del_flow_dict1)
+ deferred_br.delete_flows(**self.del_flow_dict2)
+ deferred_br.add_flow(**self.add_flow_dict2)
+ deferred_br.mod_flow(**self.mod_flow_dict2)
+ self._verify_mock_call(expected_calls)
+
+ def test_getattr_unallowed_attr(self):
+ with ovs_lib.DeferredOVSBridge(self.br) as deferred_br:
+ self.assertEqual(self.br.add_port, deferred_br.add_port)
+
+ def test_getattr_unallowed_attr(self):
+ with ovs_lib.DeferredOVSBridge(self.br) as deferred_br:
+ self.assertRaises(AttributeError, getattr, deferred_br, 'failure')
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.fakeagent.fdb_add_tun('context', self.fakebr, 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),
+ mock.call(self.fakebr, [self.lvms[0].mac, self.lvms[0].ip],
+ self.ports[0].ip, self.lvm1, self.ports[0].ofport),
+ mock.call(self.fakebr, [self.lvms[1].mac, self.lvms[1].ip],
+ self.ports[1].ip, self.lvm1, self.ports[1].ofport),
+ mock.call(self.fakebr, [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))
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.fakeagent.fdb_add_tun('context', self.fakebr, self.lvm1,
self.agent_ports, self.ofports)
mock_setup_tunnel_port.assert_called_once_with(
- self.ports[1].ip, self.lvm1.network_type)
+ self.fakebr, 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),
+ mock.call(self.fakebr, [self.lvms[0].mac, self.lvms[0].ip],
+ self.ports[0].ip, self.lvm1, self.ports[0].ofport),
+ mock.call(self.fakebr, [self.lvms[1].mac, self.lvms[1].ip],
+ self.ports[1].ip, self.lvm1, ofport),
+ mock.call(self.fakebr, [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))
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.fakeagent.fdb_add_tun('context', self.fakebr, self.lvm1,
self.agent_ports, self.ofports)
mock_setup_tunnel_port.assert_called_once_with(
- self.ports[1].ip, self.lvm1.network_type)
+ self.fakebr, 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),
+ mock.call(self.fakebr, [self.lvms[0].mac, self.lvms[0].ip],
+ self.ports[0].ip, self.lvm1, self.ports[0].ofport),
+ mock.call(self.fakebr, [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.fakeagent.fdb_remove_tun('context', self.fakebr, 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),
+ mock.call(self.fakebr, [self.lvms[0].mac, self.lvms[0].ip],
+ self.ports[0].ip, self.lvm1, self.ports[0].ofport),
+ mock.call(self.fakebr, [self.lvms[1].mac, self.lvms[1].ip],
+ self.ports[1].ip, self.lvm1, self.ports[1].ofport),
+ mock.call(self.fakebr, [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.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.fakeagent.fdb_remove_tun('context', self.fakebr, 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]],
+ mock.call(self.fakebr, [self.lvms[0].mac, self.lvms[0].ip],
+ self.ports[0].ip, self.lvm1, self.ports[0].ofport),
+ mock.call(self.fakebr,
+ [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),
+ mock.call(self.fakebr, [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)
+ self.fakebr, 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.fakeagent.fdb_remove_tun('context', self.fakebr, 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),
+ mock.call(self.fakebr, [self.lvms[0].mac, self.lvms[0].ip],
+ self.ports[0].ip, self.lvm1, self.ports[0].ofport),
+ mock.call(self.fakebr, [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_chg_ip(self):
m_setup_entry_for_arp_reply = mock.Mock()
self.fakeagent.setup_entry_for_arp_reply = m_setup_entry_for_arp_reply
- self.fakeagent.fdb_chg_ip_tun('context', self.upd_fdb_entry1_val,
- self.local_ip, self.local_vlan_map1)
+ self.fakeagent.fdb_chg_ip_tun('context', self.fakebr,
+ self.upd_fdb_entry1_val, self.local_ip,
+ self.local_vlan_map1)
expected = [
- mock.call('remove', self.lvm1.vlan, self.lvms[0].mac,
+ mock.call(self.fakebr, 'remove', self.lvm1.vlan, self.lvms[0].mac,
self.lvms[0].ip),
- mock.call('add', self.lvm1.vlan, self.lvms[1].mac,
+ mock.call(self.fakebr, 'add', self.lvm1.vlan, self.lvms[1].mac,
self.lvms[1].ip),
- mock.call('remove', self.lvm1.vlan, self.lvms[0].mac,
+ mock.call(self.fakebr, 'remove', self.lvm1.vlan, self.lvms[0].mac,
self.lvms[0].ip),
- mock.call('add', self.lvm1.vlan, self.lvms[1].mac,
+ mock.call(self.fakebr, 'add', self.lvm1.vlan, self.lvms[1].mac,
self.lvms[1].ip),
- mock.call('remove', self.lvm2.vlan, self.lvms[0].mac,
+ mock.call(self.fakebr, 'remove', self.lvm2.vlan, self.lvms[0].mac,
self.lvms[0].ip),
- mock.call('add', self.lvm2.vlan, self.lvms[2].mac,
+ mock.call(self.fakebr, 'add', self.lvm2.vlan, self.lvms[2].mac,
self.lvms[2].ip),
]
m_setup_entry_for_arp_reply.assert_has_calls(expected, any_order=True)
m_setup_entry_for_arp_reply = mock.Mock()
self.fakeagent.setup_entry_for_arp_reply = m_setup_entry_for_arp_reply
self.fakeagent.fdb_chg_ip_tun(
- 'context', self.upd_fdb_entry1, self.local_ip, {})
+ 'context', self.fakebr, self.upd_fdb_entry1, self.local_ip, {})
self.assertFalse(m_setup_entry_for_arp_reply.call_count)
def test__fdb_chg_ip_ip_is_local_ip(self):
}
m_setup_entry_for_arp_reply = mock.Mock()
self.fakeagent.setup_entry_for_arp_reply = m_setup_entry_for_arp_reply
- self.fakeagent.fdb_chg_ip_tun('context', upd_fdb_entry_val,
- self.local_ip, self.local_vlan_map1)
+ self.fakeagent.fdb_chg_ip_tun('context', self.fakebr,
+ upd_fdb_entry_val, self.local_ip,
+ self.local_vlan_map1)
self.assertFalse(m_setup_entry_for_arp_reply.call_count)
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)
+ self.agent.tun_br, tun_name, tunnel_ip, self.tunnel_type)
def test_fdb_del_port(self):
self._prepare_l2_pop_ofports()
mock.patch.object(self.mod_agent.LOG, 'error')
) as (add_tunnel_port_fn, log_error_fn):
ofport = self.agent._setup_tunnel_port(
- 'gre-1', 'remote_ip', p_const.TYPE_GRE)
+ self.agent.tun_br, '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,
self.agent.vxlan_udp_port, self.agent.dont_fragment)
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(
- 'gre-1', 'remote_ip', p_const.TYPE_GRE)
+ self.agent.tun_br, '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,
self.agent.vxlan_udp_port, self.agent.dont_fragment)
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(self.agent.tun_br, 'portname',
+ '1.2.3.4', 'vxlan')
self.assertTrue(add_tun_port_fn.called)
def test_port_unbound(self):
[[FAKE_MAC, FAKE_IP1],
n_const.FLOODING_ENTRY]}}}
with mock.patch.object(self.agent.tun_br,
- "defer_apply_on") as defer_fn:
+ "deferred") as defer_fn:
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(defer_fn.called)
[[FAKE_MAC, FAKE_IP1],
n_const.FLOODING_ENTRY]}}}
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.tun_br, 'deferred'),
+ mock.patch.object(self.agent.tun_br, 'do_action_flows'),
mock.patch.object(self.agent, '_setup_tunnel_port'),
- ) as (add_flow_fn, mod_flow_fn, add_tun_fn):
+ ) as (deferred_fn, do_action_flows_fn, add_tun_fn):
+ deferred_fn.return_value = ovs_lib.DeferredOVSBridge(
+ self.agent.tun_br)
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(add_tun_fn.called)
actions = (constants.ARP_RESPONDER_ACTIONS %
{'mac': netaddr.EUI(FAKE_MAC, dialect=netaddr.mac_unix),
'ip': netaddr.IPAddress(FAKE_IP1)})
- add_flow_fn.assert_has_calls([
- mock.call(table=constants.ARP_RESPONDER,
- priority=1,
- proto='arp',
- dl_vlan='vlan1',
- nw_dst=FAKE_IP1,
- actions=actions),
- mock.call(table=constants.UCAST_TO_TUN,
- priority=2,
- dl_vlan='vlan1',
- dl_dst=FAKE_MAC,
- actions='strip_vlan,'
- 'set_tunnel:seg1,output:2')
- ])
- mod_flow_fn.assert_called_with(table=constants.FLOOD_TO_TUN,
- dl_vlan='vlan1',
- actions='strip_vlan,'
- 'set_tunnel:seg1,output:1,2')
+ expected_calls = [
+ mock.call('add', [dict(table=constants.ARP_RESPONDER,
+ priority=1,
+ proto='arp',
+ dl_vlan='vlan1',
+ nw_dst=FAKE_IP1,
+ actions=actions),
+ dict(table=constants.UCAST_TO_TUN,
+ priority=2,
+ dl_vlan='vlan1',
+ dl_dst=FAKE_MAC,
+ actions='strip_vlan,'
+ 'set_tunnel:seg1,output:2')]),
+ mock.call('mod', [dict(table=constants.FLOOD_TO_TUN,
+ dl_vlan='vlan1',
+ actions='strip_vlan,'
+ 'set_tunnel:seg1,output:1,2')]),
+ ]
+ do_action_flows_fn.assert_has_calls(expected_calls)
def test_fdb_del_flows(self):
self._prepare_l2_pop_ofports()
[[FAKE_MAC, FAKE_IP1],
n_const.FLOODING_ENTRY]}}}
with contextlib.nested(
- mock.patch.object(self.agent.tun_br, 'mod_flow'),
- mock.patch.object(self.agent.tun_br, 'delete_flows'),
- ) as (mod_flow_fn, del_flow_fn):
+ mock.patch.object(self.agent.tun_br, 'deferred'),
+ mock.patch.object(self.agent.tun_br, 'do_action_flows'),
+ ) as (deferred_fn, do_action_flows_fn):
+ deferred_fn.return_value = ovs_lib.DeferredOVSBridge(
+ self.agent.tun_br)
self.agent.fdb_remove(None, fdb_entry)
- mod_flow_fn.assert_called_with(table=constants.FLOOD_TO_TUN,
- dl_vlan='vlan2',
- actions='strip_vlan,'
- 'set_tunnel:seg2,output:1')
- expected = [mock.call(table=constants.ARP_RESPONDER,
- proto='arp',
- dl_vlan='vlan2',
- nw_dst=FAKE_IP1),
- mock.call(table=constants.UCAST_TO_TUN,
- dl_vlan='vlan2',
- dl_dst=FAKE_MAC),
- mock.call(in_port='2')]
- del_flow_fn.assert_has_calls(expected)
+ expected_calls = [
+ mock.call('mod', [dict(table=constants.FLOOD_TO_TUN,
+ dl_vlan='vlan2',
+ actions='strip_vlan,'
+ 'set_tunnel:seg2,output:1')]),
+ mock.call('del', [dict(table=constants.ARP_RESPONDER,
+ proto='arp',
+ dl_vlan='vlan2',
+ nw_dst=FAKE_IP1),
+ dict(table=constants.UCAST_TO_TUN,
+ dl_vlan='vlan2',
+ dl_dst=FAKE_MAC),
+ dict(in_port='2')]),
+ ]
+ do_action_flows_fn.assert_has_calls(expected_calls)
def test_fdb_add_port(self):
self._prepare_l2_pop_ofports()
'segment_id': 'tun1',
'ports': {'1.1.1.1': [[FAKE_MAC, FAKE_IP1]]}}}
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.tun_br, 'deferred'),
+ mock.patch.object(self.agent.tun_br, 'do_action_flows'),
mock.patch.object(self.agent, '_setup_tunnel_port')
- ) as (add_flow_fn, mod_flow_fn, add_tun_fn):
+ ) as (deferred_fn, do_action_flows_fn, add_tun_fn):
+ deferred_br = ovs_lib.DeferredOVSBridge(self.agent.tun_br)
+ deferred_fn.return_value = deferred_br
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(add_tun_fn.called)
fdb_entry['net1']['ports']['10.10.10.10'] = [[FAKE_MAC, FAKE_IP1]]
self.agent.fdb_add(None, fdb_entry)
- add_tun_fn.assert_called_with('gre-0a0a0a0a', '10.10.10.10', 'gre')
+ add_tun_fn.assert_called_with(
+ deferred_br, 'gre-0a0a0a0a', '10.10.10.10', 'gre')
def test_fdb_del_port(self):
self._prepare_l2_pop_ofports()
'segment_id': 'tun2',
'ports': {'2.2.2.2': [n_const.FLOODING_ENTRY]}}}
with contextlib.nested(
- mock.patch.object(self.agent.tun_br, 'delete_flows'),
+ mock.patch.object(self.agent.tun_br, 'deferred'),
+ mock.patch.object(self.agent.tun_br, 'do_action_flows'),
mock.patch.object(self.agent.tun_br, 'delete_port')
- ) as (del_flow_fn, del_port_fn):
+ ) as (deferred_fn, do_action_flows_fn, delete_port_fn):
+ deferred_br = ovs_lib.DeferredOVSBridge(self.agent.tun_br)
+ deferred_fn.return_value = deferred_br
self.agent.fdb_remove(None, fdb_entry)
- del_port_fn.assert_called_once_with('gre-02020202')
+ delete_port_fn.assert_called_once_with('gre-02020202')
def test_fdb_update_chg_ip(self):
self._prepare_l2_pop_ofports()
{'before': [[FAKE_MAC, FAKE_IP1]],
'after': [[FAKE_MAC, FAKE_IP2]]}}}}
with contextlib.nested(
- mock.patch.object(self.agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.tun_br, 'delete_flows')
- ) as (add_flow_fn, del_flow_fn):
+ mock.patch.object(self.agent.tun_br, 'deferred'),
+ mock.patch.object(self.agent.tun_br, 'do_action_flows'),
+ ) as (deferred_fn, do_action_flows_fn):
+ deferred_br = ovs_lib.DeferredOVSBridge(self.agent.tun_br)
+ deferred_fn.return_value = deferred_br
self.agent.fdb_update(None, fdb_entries)
actions = (constants.ARP_RESPONDER_ACTIONS %
{'mac': netaddr.EUI(FAKE_MAC, dialect=netaddr.mac_unix),
'ip': netaddr.IPAddress(FAKE_IP2)})
- add_flow_fn.assert_called_once_with(table=constants.ARP_RESPONDER,
- priority=1,
- proto='arp',
- dl_vlan='vlan1',
- nw_dst=FAKE_IP2,
- actions=actions)
- del_flow_fn.assert_called_once_with(table=constants.ARP_RESPONDER,
- proto='arp',
- dl_vlan='vlan1',
- nw_dst=FAKE_IP1)
+ expected_calls = [
+ mock.call('add', [dict(table=constants.ARP_RESPONDER,
+ priority=1,
+ proto='arp',
+ dl_vlan='vlan1',
+ nw_dst=FAKE_IP2,
+ actions=actions)]),
+ mock.call('del', [dict(table=constants.ARP_RESPONDER,
+ proto='arp',
+ dl_vlan='vlan1',
+ nw_dst=FAKE_IP1)])
+ ]
+ do_action_flows_fn.assert_has_calls(expected_calls)
+ self.assertEqual(len(expected_calls),
+ len(do_action_flows_fn.mock_calls))
def test_recl_lv_port_to_preserve(self):
self._prepare_l2_pop_ofports()
mock.patch.object(ovs_neutron_agent.LOG, 'error')
) as (add_tunnel_port_fn, log_error_fn):
ofport = self.agent._setup_tunnel_port(
- 'gre-1', 'remote_ip', p_const.TYPE_GRE)
+ self.agent.tun_br, '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,
self.agent.vxlan_udp_port, self.agent.dont_fragment)
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(
- 'gre-1', 'remote_ip', p_const.TYPE_GRE)
+ self.agent.tun_br, '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,
self.agent.vxlan_udp_port, self.agent.dont_fragment)
) as (add_tunnel_port_fn, log_error_fn):
self.agent.dont_fragment = False
ofport = self.agent._setup_tunnel_port(
- 'gre-1', 'remote_ip', p_const.TYPE_GRE)
+ self.agent.tun_br, '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,
self.agent.vxlan_udp_port, self.agent.dont_fragment)
) 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')]
+ expected_calls = [mock.call(self.agent.tun_br, 'gre-42',
+ '100.101.102.103', 'gre')]
_setup_tunnel_port_fn.assert_has_calls(expected_calls)
def test_tunnel_sync_with_ml2_plugin(self):
) as (tunnel_sync_rpc_fn, _setup_tunnel_port_fn):
self.agent.tunnel_types = ['vxlan']
self.agent.tunnel_sync()
- expected_calls = [mock.call('vxlan-64651f0f',
+ expected_calls = [mock.call(self.agent.tun_br, 'vxlan-64651f0f',
'100.101.31.15', 'vxlan')]
_setup_tunnel_port_fn.assert_has_calls(expected_calls)
) 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',
+ _setup_tunnel_port_fn.assert_called_once_with(self.agent.tun_br,
+ 'vxlan-64646464',
'100.100.100.100',
'vxlan')
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')]
+ expected_calls = [
+ mock.call(self.agent.tun_br, 'gre-0a0a0a0a', '10.10.10.10', 'gre')]
self.agent._setup_tunnel_port.assert_has_calls(expected_calls)
def test_ovs_restart(self):