Merge "Drop of_interface option"

This commit is contained in:
Zuul 2019-05-27 15:36:13 +00:00 committed by Gerrit Code Review
commit 23e3213a07
40 changed files with 179 additions and 2051 deletions

@ -95,10 +95,6 @@ ovs_opts = [
"integration bridge to physical networks. "
"Support kernel without Open vSwitch patch port "
"support so long as it is set to True.")),
cfg.StrOpt('of_interface', default='native',
deprecated_for_removal=True,
choices=['ovs-ofctl', 'native'],
help=_("OpenFlow interface to use.")),
cfg.StrOpt('datapath_type', default=constants.OVS_DATAPATH_SYSTEM,
choices=[constants.OVS_DATAPATH_SYSTEM,
constants.OVS_DATAPATH_NETDEV],

@ -18,30 +18,20 @@
import sys
from oslo_config import cfg
from oslo_utils import importutils
from neutron.common import config as common_config
from neutron.common import profiler
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native import \
main as of_main
cfg.CONF.import_group('OVS', 'neutron.plugins.ml2.drivers.openvswitch.agent.'
'common.config')
_main_modules = {
'ovs-ofctl': 'neutron.plugins.ml2.drivers.openvswitch.agent.openflow.'
'ovs_ofctl.main',
'native': 'neutron.plugins.ml2.drivers.openvswitch.agent.openflow.'
'native.main',
}
def main():
common_config.init(sys.argv[1:])
driver_name = cfg.CONF.OVS.of_interface
mod_name = _main_modules[driver_name]
mod = importutils.import_module(mod_name)
mod.init_config()
of_main.init_config()
common_config.setup_logging()
profiler.setup("neutron-ovs-agent", cfg.CONF.host)
mod.main()
of_main.main()

@ -17,6 +17,7 @@
import functools
import random
import debtcollector
import eventlet
import netaddr
from neutron_lib import exceptions
@ -220,9 +221,8 @@ class OpenFlowSwitchMixin(object):
(dp, ofp, ofpp) = self._get_dp()
match = self._match(ofp, ofpp, match, **match_kwargs)
if isinstance(instructions, six.string_types):
# NOTE: instructions must be str for the ofctl of_interface.
# After the ofctl driver is removed, a deprecation warning
# could be added here.
debtcollector.deprecate("Use of string instruction is "
"deprecated", removal_version='U')
jsonlist = ofctl_string.ofp_instruction_from_str(
ofp, instructions)
instructions = ofproto_parser.ofp_instruction_from_jsondict(

@ -1,93 +0,0 @@
# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
# Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
# 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.
# Copyright 2011 VMware, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron_lib import constants
class OVSDVRProcessMixin(object):
"""Common logic for br-tun and br-phys' DVR_PROCESS tables.
Inheriters should provide self.dvr_process_table_id and
self.dvr_process_next_table_id.
"""
def install_dvr_process_ipv4(self, vlan_tag, gateway_ip):
# block ARP
self.add_flow(table=self.dvr_process_table_id,
priority=3,
dl_vlan=vlan_tag,
proto='arp',
nw_dst=gateway_ip,
actions='drop')
def delete_dvr_process_ipv4(self, vlan_tag, gateway_ip):
self.delete_flows(table=self.dvr_process_table_id,
dl_vlan=vlan_tag,
proto='arp',
nw_dst=gateway_ip)
def install_dvr_process_ipv6(self, vlan_tag, gateway_mac):
# block RA
self.add_flow(table=self.dvr_process_table_id,
priority=3,
dl_vlan=vlan_tag,
proto='icmp6',
icmp_type=constants.ICMPV6_TYPE_RA,
dl_src=gateway_mac,
actions='drop')
def delete_dvr_process_ipv6(self, vlan_tag, gateway_mac):
self.delete_flows(table=self.dvr_process_table_id,
dl_vlan=vlan_tag,
proto='icmp6',
icmp_type=constants.ICMPV6_TYPE_RA,
dl_src=gateway_mac)
def install_dvr_process(self, vlan_tag, vif_mac, dvr_mac_address):
self.add_flow(table=self.dvr_process_table_id,
priority=2,
dl_vlan=vlan_tag,
dl_dst=vif_mac,
actions="drop")
self.add_flow(table=self.dvr_process_table_id,
priority=1,
dl_vlan=vlan_tag,
dl_src=vif_mac,
actions="mod_dl_src:%s,resubmit(,%s)" %
(dvr_mac_address, self.dvr_process_next_table_id))
def delete_dvr_process(self, vlan_tag, vif_mac):
self.delete_flows(table=self.dvr_process_table_id,
dl_vlan=vlan_tag,
dl_dst=vif_mac)
self.delete_flows(table=self.dvr_process_table_id,
dl_vlan=vlan_tag,
dl_src=vif_mac)

@ -1,203 +0,0 @@
# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
# Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
# 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.
"""
* references
** OVS agent https://wiki.openstack.org/wiki/Ovs-flow-logic
"""
import netaddr
from neutron_lib import constants as const
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
import ovs_bridge
class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge):
"""openvswitch agent br-int specific logic."""
def setup_default_table(self):
self.setup_canary_table()
self.install_goto(dest_table_id=constants.TRANSIENT_TABLE)
self.install_normal(table_id=constants.TRANSIENT_TABLE, priority=3)
self.install_drop(table_id=constants.ARP_SPOOF_TABLE)
self.install_drop(table_id=constants.LOCAL_SWITCHING,
priority=constants.OPENFLOW_MAX_PRIORITY,
dl_vlan=constants.DEAD_VLAN_TAG)
def setup_canary_table(self):
self.install_drop(constants.CANARY_TABLE)
def check_canary_table(self):
canary_flows = self.dump_flows(constants.CANARY_TABLE)
if canary_flows == '':
return constants.OVS_RESTARTED
elif canary_flows is None:
return constants.OVS_DEAD
else:
return constants.OVS_NORMAL
def provision_local_vlan(self, port, lvid, segmentation_id):
if segmentation_id is None:
dl_vlan = 0xffff
else:
dl_vlan = segmentation_id
self.add_flow(priority=3,
in_port=port,
dl_vlan=dl_vlan,
actions="mod_vlan_vid:%s,resubmit(,%d)" % (
lvid, constants.TRANSIENT_TABLE))
def reclaim_local_vlan(self, port, segmentation_id):
if segmentation_id is None:
dl_vlan = 0xffff
else:
dl_vlan = segmentation_id
self.delete_flows(in_port=port, dl_vlan=dl_vlan)
@staticmethod
def _dvr_to_src_mac_table_id(network_type):
if network_type == const.TYPE_VLAN:
return constants.DVR_TO_SRC_MAC_VLAN
else:
return constants.DVR_TO_SRC_MAC
def install_dvr_to_src_mac(self, network_type,
vlan_tag, gateway_mac, dst_mac, dst_port):
table_id = self._dvr_to_src_mac_table_id(network_type)
self.add_flow(table=table_id,
priority=4,
dl_vlan=vlan_tag,
dl_dst=dst_mac,
actions="mod_dl_src:%s,"
"resubmit(,%d)" % (
gateway_mac, constants.TRANSIENT_TABLE))
self.add_flow(table=constants.TRANSIENT_TABLE,
priority=4,
dl_vlan=vlan_tag,
dl_dst=dst_mac,
actions="strip_vlan,output:%s" % dst_port)
def delete_dvr_to_src_mac(self, network_type, vlan_tag, dst_mac):
table_id = self._dvr_to_src_mac_table_id(network_type)
for table in (table_id, constants.TRANSIENT_TABLE):
self.delete_flows(strict=True,
priority=4,
table=table,
dl_vlan=vlan_tag,
dl_dst=dst_mac)
def add_dvr_mac_vlan(self, mac, port):
self.install_goto(table_id=constants.LOCAL_SWITCHING,
priority=4,
in_port=port,
eth_src=mac,
dest_table_id=constants.DVR_TO_SRC_MAC_VLAN)
def remove_dvr_mac_vlan(self, mac):
# REVISIT(yamamoto): match in_port as well?
self.delete_flows(table=constants.LOCAL_SWITCHING,
dl_src=mac)
def add_dvr_mac_tun(self, mac, port):
# Table LOCAL_SWITCHING will now sort DVR traffic from other
# traffic depending on in_port
self.install_goto(table_id=constants.LOCAL_SWITCHING,
priority=2,
in_port=port,
eth_src=mac,
dest_table_id=constants.DVR_TO_SRC_MAC)
def remove_dvr_mac_tun(self, mac, port):
self.delete_flows(table=constants.LOCAL_SWITCHING,
in_port=port, dl_src=mac)
def install_icmpv6_na_spoofing_protection(self, port, ip_addresses):
# Allow neighbor advertisements as long as they match addresses
# that actually belong to the port.
for ip in ip_addresses:
self.install_goto(
table_id=constants.ARP_SPOOF_TABLE, priority=2,
dl_type=const.ETHERTYPE_IPV6,
nw_proto=const.PROTO_NUM_IPV6_ICMP,
icmp_type=const.ICMPV6_TYPE_NA, nd_target=ip, in_port=port,
dest_table_id=constants.TRANSIENT_TABLE)
# Now that the rules are ready, direct icmpv6 neighbor advertisement
# traffic from the port into the anti-spoof table.
self.add_flow(table=constants.LOCAL_SWITCHING,
priority=10, dl_type=const.ETHERTYPE_IPV6,
nw_proto=const.PROTO_NUM_IPV6_ICMP,
icmp_type=const.ICMPV6_TYPE_NA, in_port=port,
actions=("resubmit(,%s)" % constants.ARP_SPOOF_TABLE))
def set_allowed_macs_for_port(self, port, mac_addresses=None,
allow_all=False):
if allow_all:
self.delete_flows(table=constants.LOCAL_SWITCHING, in_port=port)
self.delete_flows(table=constants.MAC_SPOOF_TABLE, in_port=port)
return
mac_addresses = mac_addresses or []
for address in mac_addresses:
self.install_goto(
table_id=constants.MAC_SPOOF_TABLE, priority=2,
eth_src=address, in_port=port,
dest_table_id=constants.TRANSIENT_TABLE)
# normalize so we can see if macs are the same
mac_addresses = {netaddr.EUI(mac) for mac in mac_addresses}
flows = self.dump_flows_for(table=constants.MAC_SPOOF_TABLE,
in_port=port).splitlines()
for flow in flows:
if 'dl_src' not in flow:
continue
flow_mac = flow.split('dl_src=')[1].split(' ')[0].split(',')[0]
if netaddr.EUI(flow_mac) not in mac_addresses:
self.delete_flows(table=constants.MAC_SPOOF_TABLE,
in_port=port, dl_src=flow_mac)
self.add_flow(table=constants.LOCAL_SWITCHING,
priority=9, in_port=port,
actions=("resubmit(,%s)" % constants.MAC_SPOOF_TABLE))
def install_arp_spoofing_protection(self, port, ip_addresses):
# allow ARPs as long as they match addresses that actually
# belong to the port.
for ip in ip_addresses:
self.add_flow(
table=constants.ARP_SPOOF_TABLE, priority=2,
proto='arp', arp_spa=ip, in_port=port,
actions=("resubmit(,%s)" % constants.MAC_SPOOF_TABLE))
# Now that the rules are ready, direct ARP traffic from the port into
# the anti-spoof table.
# This strategy fails gracefully because OVS versions that can't match
# on ARP headers will just process traffic normally.
self.add_flow(table=constants.LOCAL_SWITCHING,
priority=10, proto='arp', in_port=port,
actions=("resubmit(,%s)" % constants.ARP_SPOOF_TABLE))
def delete_arp_spoofing_protection(self, port):
self.delete_flows(table=constants.LOCAL_SWITCHING,
in_port=port, proto='arp')
self.delete_flows(table=constants.LOCAL_SWITCHING,
in_port=port, nw_proto=const.PROTO_NUM_IPV6_ICMP,
icmp_type=const.ICMPV6_TYPE_NA)
self.delete_arp_spoofing_allow_rules(port)
def delete_arp_spoofing_allow_rules(self, port):
self.delete_flows(table=constants.ARP_SPOOF_TABLE,
in_port=port)

@ -1,60 +0,0 @@
# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
# Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
import br_dvr_process
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
import ovs_bridge
class OVSPhysicalBridge(ovs_bridge.OVSAgentBridge,
br_dvr_process.OVSDVRProcessMixin):
"""openvswitch agent physical bridge specific logic."""
# Used by OVSDVRProcessMixin
dvr_process_table_id = constants.DVR_PROCESS_VLAN
dvr_process_next_table_id = constants.LOCAL_VLAN_TRANSLATION
def setup_default_table(self):
self.install_normal()
def provision_local_vlan(self, port, lvid, segmentation_id, distributed):
table_id = constants.LOCAL_VLAN_TRANSLATION if distributed else 0
if segmentation_id is None:
self.add_flow(table=table_id,
priority=4,
in_port=port,
dl_vlan=lvid,
actions="strip_vlan,normal")
else:
self.add_flow(table=table_id,
priority=4,
in_port=port,
dl_vlan=lvid,
actions="mod_vlan_vid:%s,normal" % segmentation_id)
def reclaim_local_vlan(self, port, lvid):
self.delete_flows(in_port=port, dl_vlan=lvid)
def add_dvr_mac_vlan(self, mac, port):
self.install_output(table_id=constants.DVR_NOT_LEARN_VLAN,
priority=2, eth_src=mac, port=port)
def remove_dvr_mac_vlan(self, mac):
# REVISIT(yamamoto): match in_port as well?
self.delete_flows(table=constants.DVR_NOT_LEARN_VLAN,
dl_src=mac)

@ -1,260 +0,0 @@
# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
# Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
# 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.
# Copyright 2011 VMware, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import functools
import netaddr
from neutron.agent.common import ovs_lib
from neutron.plugins.ml2.drivers.openvswitch.agent.common \
import constants
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
import br_dvr_process
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
import ovs_bridge
class OVSTunnelBridge(ovs_bridge.OVSAgentBridge,
br_dvr_process.OVSDVRProcessMixin):
"""openvswitch agent tunnel bridge specific logic."""
# Used by OVSDVRProcessMixin
dvr_process_table_id = constants.DVR_PROCESS
dvr_process_next_table_id = constants.PATCH_LV_TO_TUN
def setup_default_table(self, patch_int_ofport, arp_responder_enabled):
# Table 0 (default) will sort incoming traffic depending on in_port
with self.deferred() as deferred_br:
deferred_br.add_flow(priority=1,
in_port=patch_int_ofport,
actions="resubmit(,%s)" %
constants.PATCH_LV_TO_TUN)
deferred_br.add_flow(priority=0, actions="drop")
if arp_responder_enabled:
# ARP broadcast-ed request go to the local ARP_RESPONDER
# table to be locally resolved
# REVISIT(yamamoto): add arp_op=arp.ARP_REQUEST matcher?
deferred_br.add_flow(table=constants.PATCH_LV_TO_TUN,
priority=1,
proto='arp',
dl_dst="ff:ff:ff:ff:ff:ff",
actions=("resubmit(,%s)" %
constants.ARP_RESPONDER))
# PATCH_LV_TO_TUN table will handle packets coming from patch_int
# unicasts go to table UCAST_TO_TUN where remote addresses are
# learnt
deferred_br.add_flow(table=constants.PATCH_LV_TO_TUN,
priority=0,
dl_dst="00:00:00:00:00:00/01:00:00:00:00:00",
actions=("resubmit(,%s)" %
constants.UCAST_TO_TUN))
# Broadcasts/multicasts go to table FLOOD_TO_TUN that handles
# flooding
deferred_br.add_flow(table=constants.PATCH_LV_TO_TUN,
priority=0,
dl_dst="01:00:00:00:00:00/01:00:00:00:00:00",
actions=("resubmit(,%s)" %
constants.FLOOD_TO_TUN))
# Tables [tunnel_type]_TUN_TO_LV will set lvid depending on tun_id
# for each tunnel type, and resubmit to table LEARN_FROM_TUN where
# remote mac addresses will be learnt
for tunnel_type in constants.TUNNEL_NETWORK_TYPES:
deferred_br.add_flow(table=constants.TUN_TABLE[tunnel_type],
priority=0, actions="drop")
# LEARN_FROM_TUN table will have a single flow using a learn action
# to dynamically set-up flows in UCAST_TO_TUN corresponding to
# remote mac addresses (assumes that lvid has already been set by
# a previous flow)
learned_flow = ("cookie=%(cookie)s,"
"table=%(table)s,"
"priority=1,"
"hard_timeout=300,"
"NXM_OF_VLAN_TCI[0..11],"
"NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],"
"load:0->NXM_OF_VLAN_TCI[],"
"load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],"
"output:NXM_OF_IN_PORT[]" %
{'cookie': self.default_cookie,
'table': constants.UCAST_TO_TUN})
# Once remote mac addresses are learnt, output packet to patch_int
deferred_br.add_flow(table=constants.LEARN_FROM_TUN,
priority=1,
actions="learn(%s),output:%s" %
(learned_flow, patch_int_ofport))
# Egress unicast will be handled in table UCAST_TO_TUN, where
# remote mac addresses will be learned. For now, just add a
# default flow that will resubmit unknown unicasts to table
# FLOOD_TO_TUN to treat them as broadcasts/multicasts
deferred_br.add_flow(table=constants.UCAST_TO_TUN,
priority=0,
actions="resubmit(,%s)" %
constants.FLOOD_TO_TUN)
if arp_responder_enabled:
# If none of the ARP entries correspond to the requested IP,
# the broadcast-ed packet is resubmitted to the flooding table
deferred_br.add_flow(table=constants.ARP_RESPONDER,
priority=0,
actions="resubmit(,%s)" %
constants.FLOOD_TO_TUN)
# FLOOD_TO_TUN will handle flooding in tunnels based on lvid,
# for now, add a default drop action
self.install_drop(table_id=constants.FLOOD_TO_TUN)
def provision_local_vlan(self, network_type, lvid, segmentation_id,
distributed=False):
if distributed:
table_id = constants.DVR_NOT_LEARN
else:
table_id = constants.LEARN_FROM_TUN
self.add_flow(table=constants.TUN_TABLE[network_type],
priority=1,
tun_id=segmentation_id,
actions="mod_vlan_vid:%s,"
"resubmit(,%s)" %
(lvid, table_id))
def reclaim_local_vlan(self, network_type, segmentation_id):
self.delete_flows(table=constants.TUN_TABLE[network_type],
tun_id=segmentation_id)
@staticmethod
def _ofport_set_to_str(ports_set):
return ",".join(map(str, ports_set))
def install_flood_to_tun(self, vlan, tun_id, ports, deferred_br=None):
br = deferred_br if deferred_br else self
br.mod_flow(table=constants.FLOOD_TO_TUN,
dl_vlan=vlan,
actions="strip_vlan,set_tunnel:%s,output:%s" %
(tun_id, self._ofport_set_to_str(ports)))
def delete_flood_to_tun(self, vlan, deferred_br=None):
br = deferred_br if deferred_br else self
br.delete_flows(table=constants.FLOOD_TO_TUN, dl_vlan=vlan)
def install_unicast_to_tun(self, vlan, tun_id, port, mac,
deferred_br=None):
br = deferred_br if deferred_br else self
br.add_flow(table=constants.UCAST_TO_TUN,
priority=2,
dl_vlan=vlan,
dl_dst=mac,
actions="strip_vlan,set_tunnel:%s,output:%s" %
(tun_id, port))
def delete_unicast_to_tun(self, vlan, mac, deferred_br=None):
br = deferred_br if deferred_br else self
if mac is None:
br.delete_flows(table=constants.UCAST_TO_TUN,
dl_vlan=vlan)
else:
br.delete_flows(table=constants.UCAST_TO_TUN,
dl_vlan=vlan,
dl_dst=mac)
def install_arp_responder(self, vlan, ip, mac, deferred_br=None):
br = deferred_br if deferred_br else self
actions = constants.ARP_RESPONDER_ACTIONS % {
'mac': netaddr.EUI(mac, dialect=netaddr.mac_unix),
'ip': netaddr.IPAddress(ip),
}
br.add_flow(table=constants.ARP_RESPONDER,
priority=1,
proto='arp',
dl_vlan=vlan,
nw_dst='%s' % ip,
actions=actions)
def delete_arp_responder(self, vlan, ip, deferred_br=None):
br = deferred_br if deferred_br else self
if ip is None:
br.delete_flows(table=constants.ARP_RESPONDER,
proto='arp',
dl_vlan=vlan)
else:
br.delete_flows(table=constants.ARP_RESPONDER,
proto='arp',
dl_vlan=vlan,
nw_dst='%s' % ip)
def setup_tunnel_port(self, network_type, port, deferred_br=None):
br = deferred_br if deferred_br else self
br.add_flow(priority=1,
in_port=port,
actions="resubmit(,%s)" %
constants.TUN_TABLE[network_type])
def cleanup_tunnel_port(self, port, deferred_br=None):
br = deferred_br if deferred_br else self
br.delete_flows(in_port=port)
def add_dvr_mac_tun(self, mac, port):
# Table DVR_NOT_LEARN ensures unique dvr macs in the cloud
# are not learnt, as they may result in flow explosions
self.install_output(table_id=constants.DVR_NOT_LEARN,
priority=1,
eth_src=mac,
port=port)
def remove_dvr_mac_tun(self, mac):
# REVISIT(yamamoto): match in_port as well?
self.delete_flows(table=constants.DVR_NOT_LEARN,
dl_src=mac)
def deferred(self):
return DeferredOVSTunnelBridge(self)
class DeferredOVSTunnelBridge(ovs_lib.DeferredOVSBridge):
_METHODS = [
'install_unicast_to_tun',
'delete_unicast_to_tun',
'install_flood_to_tun',
'delete_flood_to_tun',
'install_arp_responder',
'delete_arp_responder',
'setup_tunnel_port',
'cleanup_tunnel_port',
]
def __getattr__(self, name):
if name in self._METHODS:
m = getattr(self.br, name)
return functools.partial(m, deferred_br=self)
return super(DeferredOVSTunnelBridge, self).__getattr__(name)

@ -1,36 +0,0 @@
# Copyright (C) 2015 VA Linux Systems Japan K.K.
# Copyright (C) 2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
import br_int
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
import br_phys
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
import br_tun
from neutron.plugins.ml2.drivers.openvswitch.agent import ovs_neutron_agent
def init_config():
pass
def main():
bridge_classes = {
'br_int': br_int.OVSIntegrationBridge,
'br_phys': br_phys.OVSPhysicalBridge,
'br_tun': br_tun.OVSTunnelBridge,
}
ovs_neutron_agent.main(bridge_classes)

@ -1,113 +0,0 @@
# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
# Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import re
from oslo_log import log as logging
LOG = logging.getLogger(__name__)
# Field name mappings (from os-ken to ovs-ofctl)
_keywords = {
'eth_src': 'dl_src',
'eth_dst': 'dl_dst',
'ipv4_src': 'nw_src',
'ipv4_dst': 'nw_dst',
'table_id': 'table',
}
class OpenFlowSwitchMixin(object):
"""Mixin to provide common convenient routines for an openflow switch."""
@staticmethod
def _conv_args(kwargs):
for our_name, ovs_ofctl_name in _keywords.items():
if our_name in kwargs:
kwargs[ovs_ofctl_name] = kwargs.pop(our_name)
return kwargs
def dump_flows(self, table_id):
return self.dump_flows_for_table(table_id)
def dump_flows_all_tables(self):
return self.dump_all_flows()
def install_goto_next(self, table_id):
self.install_goto(table_id=table_id, dest_table_id=table_id + 1)
def install_output(self, port, table_id=0, priority=0, **kwargs):
self.add_flow(table=table_id,
priority=priority,
actions="output:%s" % port,
**self._conv_args(kwargs))
def install_normal(self, table_id=0, priority=0, **kwargs):
self.add_flow(table=table_id,
priority=priority,
actions="normal",
**self._conv_args(kwargs))
def install_goto(self, dest_table_id, table_id=0, priority=0, **kwargs):
self.add_flow(table=table_id,
priority=priority,
actions="resubmit(,%s)" % dest_table_id,
**self._conv_args(kwargs))
def install_drop(self, table_id=0, priority=0, **kwargs):
self.add_flow(table=table_id,
priority=priority,
actions="drop",
**self._conv_args(kwargs))
def install_instructions(self, instructions,
table_id=0, priority=0, **kwargs):
self.add_flow(table=table_id,
priority=priority,
actions=instructions,
**self._conv_args(kwargs))
def uninstall_flows(self, **kwargs):
# NOTE(yamamoto): super() points to ovs_lib.OVSBridge.
# See ovs_bridge.py how this class is actually used.
super(OpenFlowSwitchMixin, self).delete_flows(
**self._conv_args(kwargs))
def _filter_flows(self, flows):
cookie_list = self.reserved_cookies
LOG.debug("Bridge cookies used to filter flows: %s",
cookie_list)
cookie_re = re.compile('cookie=(0x[A-Fa-f0-9]*)')
table_re = re.compile('table=([0-9]*)')
for flow in flows:
fl_cookie = cookie_re.search(flow)
if not fl_cookie:
continue
fl_cookie = fl_cookie.group(1)
if int(fl_cookie, 16) not in cookie_list:
fl_table = table_re.search(flow)
if not fl_table:
continue
fl_table = fl_table.group(1)
yield flow, fl_cookie, fl_table
def cleanup_flows(self):
flows = self.dump_flows_all_tables()
for flow, cookie, table in self._filter_flows(flows):
# deleting a stale flow should be rare.
# it might deserve some attention
LOG.warning("Deleting flow %s", flow)
self.delete_flows(cookie=cookie + '/-1', table=table)

@ -1,33 +0,0 @@
# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
# Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron.agent.common import ovs_lib
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow \
import br_cookie
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
import ofswitch
class OVSAgentBridge(ofswitch.OpenFlowSwitchMixin,
br_cookie.OVSBridgeCookieMixin, ovs_lib.OVSBridge):
"""Common code for bridges used by OVS agent"""
def setup_controllers(self, conf):
self.del_controller()
def drop_port(self, in_port):
self.install_drop(priority=2, in_port=in_port)

@ -17,13 +17,12 @@ import functools
import fixtures
import netaddr
from neutron_lib import constants
from oslo_config import cfg
from oslo_utils import uuidutils
from neutron.common import utils as common_utils
from neutron.plugins.ml2.drivers.openvswitch.agent.common import (
constants as ovs_consts)
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl import (
br_int)
from neutron.tests.common import machine_fixtures
from neutron.tests.common import net_helpers
@ -400,11 +399,17 @@ class OVSConnectionTester(OVSBaseConnectionTester):
"""
def __init__(self, ip_cidr, br_int_cls):
super(OVSConnectionTester, self).__init__(ip_cidr)
self.br_int_cls = br_int_cls
def _setUp(self):
super(OVSConnectionTester, self)._setUp()
br_name = self.useFixture(
net_helpers.OVSBridgeFixture()).bridge.br_name
self.bridge = br_int.OVSIntegrationBridge(br_name)
self.bridge = self.br_int_cls(br_name)
self.bridge.set_secure_mode()
self.bridge.setup_controllers(cfg.CONF)
self.bridge.setup_default_table()
machines = self.useFixture(
machine_fixtures.PeerMachines(

@ -197,7 +197,6 @@ class OVSConfigFixture(ConfigFixture):
'ovs': {
'local_ip': local_ip,
'integration_bridge': self._generate_integration_bridge(),
'of_interface': host_desc.of_interface,
'bridge_mappings': '%s:%s' % (PHYSICAL_NETWORK_NAME, ext_dev)
},
'securitygroup': {
@ -236,13 +235,12 @@ class OVSConfigFixture(ConfigFixture):
})
def _setUp(self):
if self.config['ovs']['of_interface'] == 'native':
self.config['ovs'].update({
'of_listen_port': self.useFixture(
port.ExclusivePort(constants.PROTO_NAME_TCP,
start=OVS_OF_PORT_LISTEN_START,
end=OVS_OF_PORT_LISTEN_END)).port
})
self.config['ovs'].update({
'of_listen_port': self.useFixture(
port.ExclusivePort(constants.PROTO_NAME_TCP,
start=OVS_OF_PORT_LISTEN_START,
end=OVS_OF_PORT_LISTEN_END)).port
})
super(OVSConfigFixture, self)._setUp()
def _generate_integration_bridge(self):

@ -72,14 +72,12 @@ class HostDescription(object):
under?
"""
def __init__(self, l3_agent=False, dhcp_agent=False,
of_interface='ovs-ofctl',
l2_agent_type=constants.AGENT_TYPE_OVS,
firewall_driver='noop', availability_zone=None,
l3_agent_mode=None):
self.l2_agent_type = l2_agent_type
self.l3_agent = l3_agent
self.dhcp_agent = dhcp_agent
self.of_interface = of_interface
self.firewall_driver = firewall_driver
self.availability_zone = availability_zone
self.l3_agent_mode = l3_agent_mode

@ -25,7 +25,6 @@ from neutron.tests.fullstack import base
from neutron.tests.fullstack.resources import config
from neutron.tests.fullstack.resources import environment
from neutron.tests.fullstack.resources import machine
from neutron.tests.fullstack import utils
from neutron.tests.unit import testlib_api
load_tests = testlib_api.module_load_tests
@ -37,7 +36,6 @@ LOG = logging.getLogger(__name__)
class BaseConnectivitySameNetworkTest(base.BaseFullStackTestCase):
of_interface = None
arp_responder = False
use_dhcp = True
@ -50,7 +48,6 @@ class BaseConnectivitySameNetworkTest(base.BaseFullStackTestCase):
# agent types present on machines.
environment.HostDescription(
l3_agent=self.l2_pop,
of_interface=self.of_interface,
l2_agent_type=self.l2_agent_type,
dhcp_agent=self.use_dhcp,
)
@ -104,7 +101,7 @@ class BaseConnectivitySameNetworkTest(base.BaseFullStackTestCase):
class TestOvsConnectivitySameNetwork(BaseConnectivitySameNetworkTest):
l2_agent_type = constants.AGENT_TYPE_OVS
network_scenarios = [
scenarios = [
('VXLAN', {'network_type': 'vxlan',
'l2_pop': False}),
('GRE-l2pop-arp_responder', {'network_type': 'gre',
@ -112,8 +109,6 @@ class TestOvsConnectivitySameNetwork(BaseConnectivitySameNetworkTest):
'arp_responder': True}),
('VLANs', {'network_type': 'vlan',
'l2_pop': False})]
scenarios = testscenarios.multiply_scenarios(
network_scenarios, utils.get_ovs_interface_scenarios())
def test_connectivity(self):
self._test_connectivity()
@ -125,7 +120,7 @@ class TestOvsConnectivitySameNetworkOnOvsBridgeControllerStop(
num_hosts = 2
l2_agent_type = constants.AGENT_TYPE_OVS
network_scenarios = [
scenarios = [
('VXLAN', {'network_type': 'vxlan',
'l2_pop': False}),
('GRE and l2pop', {'network_type': 'gre',
@ -133,12 +128,6 @@ class TestOvsConnectivitySameNetworkOnOvsBridgeControllerStop(
('VLANs', {'network_type': 'vlan',
'l2_pop': False})]
# Do not test for CLI ofctl interface as controller is irrelevant for CLI
scenarios = testscenarios.multiply_scenarios(
network_scenarios,
[(m, v) for (m, v) in utils.get_ovs_interface_scenarios()
if v['of_interface'] != 'ovs-ofctl'])
def _test_controller_timeout_does_not_break_connectivity(self,
kill_signal=None):
# Environment preparation is effectively the same as connectivity test
@ -203,7 +192,6 @@ class TestConnectivitySameNetworkNoDhcp(BaseConnectivitySameNetworkTest):
use_dhcp = False
network_type = 'vxlan'
l2_pop = False
of_interface = 'native'
def test_connectivity(self):
self._test_connectivity()
@ -228,8 +216,8 @@ class TestUninterruptedConnectivityOnL2AgentRestart(
'l2_pop': False}),
]
scenarios = (
testscenarios.multiply_scenarios(ovs_agent_scenario, network_scenarios,
utils.get_ovs_interface_scenarios()) +
testscenarios.multiply_scenarios(ovs_agent_scenario,
network_scenarios) +
testscenarios.multiply_scenarios(lb_agent_scenario, network_scenarios)
)

@ -44,7 +44,6 @@ class FirewallMigrationTestCase(base.BaseFullStackTestCase):
host_descriptions = [
environment.HostDescription(
l3_agent=False,
of_interface='native',
l2_agent_type=constants.AGENT_TYPE_OVS,
firewall_driver='iptables_hybrid',
dhcp_agent=False,

@ -27,13 +27,11 @@ from neutron.tests.fullstack.resources import machine
class BaseLoggingTestCase(base.BaseFullStackTestCase):
of_interface = None
number_of_hosts = 1
def setUp(self):
host_desc = [
environment.HostDescription(
of_interface=self.of_interface,
l2_agent_type=constants.AGENT_TYPE_OVS,
firewall_driver='openvswitch',
dhcp_agent=True) for _ in range(self.number_of_hosts)]
@ -90,8 +88,6 @@ class BaseLoggingTestCase(base.BaseFullStackTestCase):
class TestLogging(BaseLoggingTestCase):
of_interface = 'native'
def _create_network_log(self, resource_type,
resource_id=None, target_id=None):
return self.safe_client.create_network_log(

@ -18,7 +18,6 @@ from neutron_lib import constants
from neutron_lib.services.qos import constants as qos_consts
from neutronclient.common import exceptions
from oslo_utils import uuidutils
import testscenarios
from neutron.agent.common import ovs_lib
from neutron.agent.linux import tc_lib
@ -28,7 +27,6 @@ from neutron.tests.fullstack import base
from neutron.tests.fullstack.resources import config as fullstack_config
from neutron.tests.fullstack.resources import environment
from neutron.tests.fullstack.resources import machine
from neutron.tests.fullstack import utils as fullstack_utils
from neutron.tests.unit import testlib_api
from neutron.conf.plugins.ml2.drivers import linuxbridge as \
@ -48,7 +46,6 @@ DSCP_MARK = 16
class BaseQoSRuleTestCase(object):
of_interface = None
number_of_hosts = 1
physical_network = None
@ -63,7 +60,6 @@ class BaseQoSRuleTestCase(object):
host_desc = [
environment.HostDescription(
l3_agent=False,
of_interface=self.of_interface,
l2_agent_type=self.l2_agent_type
) for _ in range(self.number_of_hosts)]
env_desc = environment.EnvironmentDescription(
@ -344,12 +340,10 @@ class _TestBwLimitQoS(BaseQoSRuleTestCase):
class TestBwLimitQoSOvs(_TestBwLimitQoS, base.BaseFullStackTestCase):
l2_agent_type = constants.AGENT_TYPE_OVS
direction_scenarios = [
scenarios = [
('ingress', {'direction': constants.INGRESS_DIRECTION}),
('egress', {'direction': constants.EGRESS_DIRECTION})
]
scenarios = testscenarios.multiply_scenarios(
direction_scenarios, fullstack_utils.get_ovs_interface_scenarios())
@staticmethod
def _get_expected_burst_value(limit, direction):
@ -520,7 +514,6 @@ class _TestDscpMarkingQoS(BaseQoSRuleTestCase):
class TestDscpMarkingQoSOvs(_TestDscpMarkingQoS, base.BaseFullStackTestCase):
scenarios = fullstack_utils.get_ovs_interface_scenarios()
l2_agent_type = constants.AGENT_TYPE_OVS
def _wait_for_dscp_marking_rule_applied(self, vm, dscp_mark):
@ -670,11 +663,9 @@ class _TestMinBwQoS(BaseQoSRuleTestCase):
class TestMinBwQoSOvs(_TestMinBwQoS, base.BaseFullStackTestCase):
l2_agent_type = constants.AGENT_TYPE_OVS
direction_scenarios = [
scenarios = [
('egress', {'direction': constants.EGRESS_DIRECTION})
]
scenarios = testscenarios.multiply_scenarios(
direction_scenarios, fullstack_utils.get_ovs_interface_scenarios())
def _wait_for_min_bw_rule_applied(self, vm, min_bw, direction):
if direction == constants.EGRESS_DIRECTION:

@ -40,13 +40,10 @@ class OVSVersionChecker(object):
class BaseSecurityGroupsSameNetworkTest(base.BaseFullStackTestCase):
of_interface = None
def setUp(self):
debug_iptables = self.firewall_driver.startswith("iptables")
host_descriptions = [
environment.HostDescription(
of_interface=self.of_interface,
l2_agent_type=self.l2_agent_type,
firewall_driver=self.firewall_driver,
dhcp_agent=True) for _ in range(self.num_hosts)]
@ -92,17 +89,10 @@ class TestSecurityGroupsSameNetwork(BaseSecurityGroupsSameNetworkTest):
# because of that using only one host is enough
('ovs-hybrid', {
'firewall_driver': 'iptables_hybrid',
'of_interface': 'native',
'l2_agent_type': constants.AGENT_TYPE_OVS,
'num_hosts': 1}),
('ovs-openflow-cli', {
('ovs-openflow', {
'firewall_driver': 'openvswitch',
'of_interface': 'ovs-ofctl',
'l2_agent_type': constants.AGENT_TYPE_OVS,
'num_hosts': 2}),
('ovs-openflow-native', {
'firewall_driver': 'openvswitch',
'of_interface': 'native',
'l2_agent_type': constants.AGENT_TYPE_OVS,
'num_hosts': 2}),
('linuxbridge-iptables', {

@ -1,18 +0,0 @@
# 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.
def get_ovs_interface_scenarios():
return [
('openflow-cli', {'of_interface': 'ovs-ofctl'}),
('openflow-native', {'of_interface': 'native'}),
]

@ -17,6 +17,7 @@
import random
import eventlet
import fixtures
import mock
from neutron_lib import constants as n_const
from neutron_lib.utils import net
@ -35,19 +36,77 @@ from neutron.conf.plugins.ml2.drivers import ovs_conf
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants
from neutron.plugins.ml2.drivers.openvswitch.agent.extension_drivers \
import qos_driver as ovs_qos_driver
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
import br_int
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
import br_phys
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
import br_tun
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native \
import main as main_mod
from neutron.plugins.ml2.drivers.openvswitch.agent import ovs_neutron_agent \
as ovs_agent
from neutron.tests.common import net_helpers
from neutron.tests.functional.agent.linux import base
class OVSAgentTestFramework(base.BaseOVSLinuxTestCase):
class OVSOFControllerHelper(object):
"""Helper class that runs os-ken openflow controller."""
def start_of_controller(self, conf):
self.br_int_cls = None
self.br_tun_cls = None
self.br_phys_cls = None
self.init_done = False
self.init_done_ev = eventlet.event.Event()
self.main_ev = eventlet.event.Event()
self.addCleanup(self._kill_main)
retry_count = 3
while True:
# Try a few different ports as a port conflict
# causes the test to fail.
conf.set_override('of_listen_port',
net_helpers.get_free_namespace_port(
n_const.PROTO_NAME_TCP),
group='OVS')
cfg.CONF.set_override('of_listen_port',
conf.OVS.of_listen_port,
group='OVS')
main_mod.init_config()
self._main_thread = eventlet.spawn(self._kick_main)
# Wait for _kick_main -> openflow main -> _agent_main
# NOTE(yamamoto): This complexity came from how we run openflow
# controller. Main routine blocks while running the embedded
# openflow controller. In that case, the agent rpc_loop runs in
# another thread. However, for FT we need to run setUp() and
# test_xxx() in the same thread. So I made this run openflow main
# in a separate thread instead.
try:
while not self.init_done:
self.init_done_ev.wait()
break
except fixtures.TimeoutException:
self._kill_main()
retry_count -= 1
if retry_count < 0:
raise Exception('port allocation failed')
def _kick_main(self):
with mock.patch.object(ovs_agent, 'main', self._agent_main):
main_mod.main()
def _kill_main(self):
self.main_ev.send()
self._main_thread.wait()
def _agent_main(self, bridge_classes):
self.br_int_cls = bridge_classes['br_int']
self.br_phys_cls = bridge_classes['br_phys']
self.br_tun_cls = bridge_classes['br_tun']
# signal to setUp()
self.init_done = True
self.init_done_ev.send()
self.main_ev.wait()
class OVSAgentTestFramework(base.BaseOVSLinuxTestCase, OVSOFControllerHelper):
def setUp(self):
super(OVSAgentTestFramework, self).setUp()
@ -68,6 +127,7 @@ class OVSAgentTestFramework(base.BaseOVSLinuxTestCase):
self.config = self._configure_agent()
self.driver = interface.OVSInterfaceDriver(self.config)
self.namespace = self.useFixture(net_helpers.NamespaceFixture()).name
self.start_of_controller(self.config)
def _get_config_opts(self):
config = cfg.ConfigOpts()
@ -95,9 +155,9 @@ class OVSAgentTestFramework(base.BaseOVSLinuxTestCase):
def _bridge_classes(self):
return {
'br_int': br_int.OVSIntegrationBridge,
'br_phys': br_phys.OVSPhysicalBridge,
'br_tun': br_tun.OVSTunnelBridge
'br_int': self.br_int_cls,
'br_phys': self.br_phys_cls,
'br_tun': self.br_tun_cls
}
def create_agent(self, create_tunnels=True, ancillary_bridge=None,

@ -34,6 +34,7 @@ from neutron.cmd.sanity import checks
from neutron.conf.agent import securitygroups_rpc as security_config
from neutron.tests.common import conn_testers
from neutron.tests.common import helpers
from neutron.tests.functional.agent.l2 import base as l2_base
from neutron.tests.functional.agent.linux import base as linux_base
from neutron.tests.functional import constants as test_constants
@ -131,8 +132,12 @@ class BaseFirewallTestCase(linux_base.BaseOVSLinuxTestCase):
"OVS>=2.5). More info at "
"https://github.com/openvswitch/ovs/blob/master/"
"FAQ.md")
self.of_helper = l2_base.OVSOFControllerHelper()
self.of_helper.addCleanup = self.addCleanup
self.of_helper.start_of_controller(cfg.CONF)
tester = self.useFixture(
conn_testers.OVSConnectionTester(self.ip_cidr))
conn_testers.OVSConnectionTester(self.ip_cidr,
self.of_helper.br_int_cls))
firewall_drv = openvswitch_firewall.OVSFirewallDriver(tester.bridge)
return tester, firewall_drv

@ -40,8 +40,10 @@ class TestOVSAgent(base.OVSAgentTestFramework):
def test_no_stale_flows_after_port_delete(self):
def find_drop_flow(ofport, flows):
for flow in flows.split("\n"):
if "in_port=%d" % ofport in flow and "actions=drop" in flow:
for flow in flows:
# flow.instruction == [] means actions=drop
if (not flow.instructions and
('in_port', ofport) in flow.match.items()):
return True
return False
@ -96,6 +98,7 @@ class TestOVSAgent(base.OVSAgentTestFramework):
('br_int', 'br_tun', 'br_phys')):
actual = self.ovs.db_get_val('Bridge', br_name, 'datapath_type')
self.assertEqual(expected, actual)
self.stop_agent(agent, self.agent_thread)
def test_datapath_type_change(self):
self._check_datapath_type_netdev('system')

@ -13,15 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import eventlet
import fixtures
import mock
import testscenarios
from neutron_lib import constants as n_const
from oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_utils import importutils
from testtools.content import text_content
from neutron.agent.common import ovs_lib
@ -35,11 +29,11 @@ from neutron.plugins.ml2.drivers.openvswitch.agent \
from neutron.tests.common import base as common_base
from neutron.tests.common import helpers
from neutron.tests.common import net_helpers
from neutron.tests.functional.agent.l2 import base as l2_base
from neutron.tests.functional.agent import test_ovs_lib
from neutron.tests.functional import base
from neutron.tests import tools
load_tests = testscenarios.load_tests_apply_scenarios
OVS_TRACE_FINAL_FLOW = 'Final flow'
OVS_TRACE_DATAPATH_ACTIONS = 'Datapath actions'
@ -47,52 +41,18 @@ cfg.CONF.import_group('OVS', 'neutron.plugins.ml2.drivers.openvswitch.agent.'
'common.config')
class OVSAgentTestBase(test_ovs_lib.OVSBridgeTestBase):
scenarios = [
('ofctl', {'main_module': ('neutron.plugins.ml2.drivers.openvswitch.'
'agent.openflow.ovs_ofctl.main')}),
('native', {'main_module': ('neutron.plugins.ml2.drivers.openvswitch.'
'agent.openflow.native.main')})]
class OVSAgentTestBase(test_ovs_lib.OVSBridgeTestBase,
base.BaseSudoTestCase,
l2_base.OVSOFControllerHelper):
def setUp(self):
super(OVSAgentTestBase, self).setUp()
self.br = self.useFixture(net_helpers.OVSBridgeFixture()).bridge
self.of_interface_mod = importutils.import_module(self.main_module)
self.br_int_cls = None
self.br_tun_cls = None
self.br_phys_cls = None
self.br_int = None
self.init_done = False
self.init_done_ev = eventlet.event.Event()
self.main_ev = eventlet.event.Event()
self.addCleanup(self._kill_main)
retry_count = 3
while True:
cfg.CONF.set_override('of_listen_port',
net_helpers.get_free_namespace_port(
n_const.PROTO_NAME_TCP),
group='OVS')
self.of_interface_mod.init_config()
self._main_thread = eventlet.spawn(self._kick_main)
# Wait for _kick_main -> of_interface main -> _agent_main
# NOTE(yamamoto): This complexity came from how "native"
# of_interface runs its openflow controller. "native"
# of_interface's main routine blocks while running the
# embedded openflow controller. In that case, the agent
# rpc_loop runs in another thread. However, for FT we
# need to run setUp() and test_xxx() in the same thread.
# So I made this run of_interface's main in a separate
# thread instead.
try:
while not self.init_done:
self.init_done_ev.wait()
break
except fixtures.TimeoutException:
self._kill_main()
retry_count -= 1
if retry_count < 0:
raise Exception('port allocation failed')
self.start_of_controller(cfg.CONF)
self.br_int = self.br_int_cls(self.br.br_name)
self.br_int.set_secure_mode()
self.br_int.setup_controllers(cfg.CONF)
self.br_int.setup_default_table()
def _run_trace(self, brname, spec):
required_keys = [OVS_TRACE_FINAL_FLOW, OVS_TRACE_DATAPATH_ACTIONS]
@ -112,29 +72,6 @@ class OVSAgentTestBase(test_ovs_lib.OVSBridgeTestBase):
return trace
def _kick_main(self):
with mock.patch.object(ovsagt, 'main', self._agent_main):
self.of_interface_mod.main()
def _kill_main(self):
self.main_ev.send()
self._main_thread.wait()
def _agent_main(self, bridge_classes):
self.br_int_cls = bridge_classes['br_int']
self.br_phys_cls = bridge_classes['br_phys']
self.br_tun_cls = bridge_classes['br_tun']
self.br_int = self.br_int_cls(self.br.br_name)
self.br_int.set_secure_mode()
self.br_int.setup_controllers(cfg.CONF)
self.br_int.setup_default_table()
# signal to setUp()
self.init_done = True
self.init_done_ev.send()
self.main_ev.wait()
class ARPSpoofTestCase(OVSAgentTestBase):
def setUp(self):
@ -357,9 +294,7 @@ class DeleteFlowsTestCase(OVSAgentTestBase):
class OVSFlowTestCase(OVSAgentTestBase):
"""Tests defined in this class use ovs-appctl ofproto/trace commands,
which simulate processing of imaginary packets, to check desired actions
are correctly set up by OVS flows. In this way, subtle variations in
flows between of_interface drivers are absorbed and the same tests work
against those drivers.
are correctly set up by OVS flows.
"""
def setUp(self):
@ -466,9 +401,6 @@ class OVSFlowTestCase(OVSAgentTestBase):
self.assertIn("pop_vlan,", trace["Datapath actions"])
def test_bundled_install(self):
if 'ovs_ofctl' in self.main_module:
self.skip("ovs-ofctl of_interface doesn't have bundled()")
kwargs = {'in_port': 345, 'vlan_tci': 0x1321}
dst_p = self.useFixture(
net_helpers.OVSPortFixture(self.br_tun, self.namespace)).port

@ -27,8 +27,6 @@ from neutron.plugins.ml2.drivers.openvswitch.agent import (
ovs_agent_extension_api as ovs_ext_api)
from neutron.plugins.ml2.drivers.openvswitch.agent.common import (
constants as ovs_consts)
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl import (
ovs_bridge)
from neutron.services.logapi.drivers.openvswitch import (
ovs_firewall_log as ovs_fw_log)
from neutron.tests.functional.agent import test_firewall
@ -62,11 +60,12 @@ class LoggingExtensionTestFramework(test_firewall.BaseFirewallTestCase):
self.log_driver = self.initialize_ovs_fw_log()
def initialize_ovs_fw_log(self):
mock.patch('os_ken.base.app_manager.AppManager.get_instance').start()
self.int_br = ovs_ext_api.OVSCookieBridge(
self.of_helper.br_int_cls(self.tester.bridge.br_name))
self.tun_br = self.of_helper.br_tun_cls('br-tun')
agent_api = ovs_ext_api.OVSAgentExtensionAPI(
ovs_bridge.OVSAgentBridge(self.tester.bridge.br_name),
ovs_bridge.OVSAgentBridge('br-tun'),
{'physnet1': ovs_bridge.OVSAgentBridge('br-physnet1')})
self.int_br, self.tun_br,
{'physnet1': self.of_helper.br_phys_cls('br-physnet1')})
log_driver = ovs_fw_log.OVSFirewallLoggingDriver(agent_api)
log_driver.initialize(self.resource_rpc)
return log_driver

@ -32,7 +32,7 @@ from neutron.objects.qos import rule
from neutron.plugins.ml2.drivers.openvswitch.agent import (
ovs_agent_extension_api as ovs_ext_api)
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl import (
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native import (
ovs_bridge)
from neutron.tests import base
@ -224,10 +224,14 @@ class QosExtensionBaseTestCase(base.BaseTestCase):
self.qos_ext = qos.QosAgentExtension()
self.context = context.get_admin_context()
self.connection = mock.Mock()
os_ken_app = mock.Mock()
self.agent_api = ovs_ext_api.OVSAgentExtensionAPI(
ovs_bridge.OVSAgentBridge('br-int'),
ovs_bridge.OVSAgentBridge('br-tun'),
{'phynet1': ovs_bridge.OVSAgentBridge('br-phynet1')})
ovs_bridge.OVSAgentBridge(
'br-int', os_ken_app=os_ken_app),
ovs_bridge.OVSAgentBridge(
'br-tun', os_ken_app=os_ken_app),
{'phynet1': ovs_bridge.OVSAgentBridge(
'br-phynet1', os_ken_app=os_ken_app)})
self.qos_ext.consume_api(self.agent_api)
# Don't rely on used driver

@ -26,7 +26,7 @@ from neutron.agent.linux.openvswitch_firewall import exceptions
from neutron.agent.linux.openvswitch_firewall import firewall as ovsfw
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \
as ovs_consts
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native \
import ovs_bridge
from neutron.tests import base
@ -752,7 +752,7 @@ class TestCookieContext(base.BaseTestCase):
self.execute = mock.patch.object(
utils, "execute", spec=utils.execute).start()
bridge = ovs_bridge.OVSAgentBridge('foo')
bridge = ovs_bridge.OVSAgentBridge('foo', os_ken_app=mock.Mock())
mock.patch.object(
ovsfw.OVSFirewallDriver, 'initialize_bridge',
return_value=bridge.deferred(

@ -23,7 +23,7 @@ from neutron.plugins.ml2.drivers.openvswitch.agent import (
ovs_agent_extension_api as ovs_ext_api)
from neutron.plugins.ml2.drivers.openvswitch.agent.extension_drivers import (
qos_driver)
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl import (
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native import (
ovs_bridge)
from neutron.tests.unit.plugins.ml2.drivers.openvswitch.agent import (
ovs_test_base)
@ -41,10 +41,14 @@ class QosOVSAgentDriverTestCase(ovs_test_base.OVSAgentConfigTestBase):
self.qos_driver = qos_driver.QosOVSAgentDriver()
self.mock_clear_minimum_bandwidth_qos = mock.patch.object(
self.qos_driver, '_minimum_bandwidth_initialize').start()
os_ken_app = mock.Mock()
self.agent_api = ovs_ext_api.OVSAgentExtensionAPI(
ovs_bridge.OVSAgentBridge('br-int'),
ovs_bridge.OVSAgentBridge('br-tun'),
{'phys1': ovs_bridge.OVSAgentBridge('br-phys1')})
ovs_bridge.OVSAgentBridge(
'br-int', os_ken_app=os_ken_app),
ovs_bridge.OVSAgentBridge(
'br-tun', os_ken_app=os_ken_app),
{'phys1': ovs_bridge.OVSAgentBridge(
'br-phys1', os_ken_app=os_ken_app)})
self.qos_driver.consume_api(self.agent_api)
self.qos_driver.initialize()
self.qos_driver.br_int = mock.Mock()

@ -1,175 +0,0 @@
# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
# Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from neutron_lib import constants
from neutron.tests.unit.plugins.ml2.drivers.openvswitch.agent \
import ovs_test_base
call = mock.call # short hand
class OVSBridgeTestBase(ovs_test_base.OVSOFCtlTestBase):
def setup_bridge_mock(self, name, cls):
self.br = cls(name)
mock_add_flow = mock.patch.object(self.br, 'add_flow').start()
mock_mod_flow = mock.patch.object(self.br, 'mod_flow').start()
mock_delete_flows = mock.patch.object(self.br, 'delete_flows').start()
self.mock = mock.Mock()
self.mock.attach_mock(mock_add_flow, 'add_flow')
self.mock.attach_mock(mock_mod_flow, 'mod_flow')
self.mock.attach_mock(mock_delete_flows, 'delete_flows')
def test_drop_port(self):
in_port = 2345
self.br.drop_port(in_port=in_port)
expected = [
call.add_flow(priority=2, table=0, actions='drop',
in_port=in_port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_install_goto(self):
dest_table_id = 123
priority = 99
in_port = 666
self.br.install_goto(dest_table_id=dest_table_id,
priority=priority, in_port=in_port)
expected = [
call.add_flow(priority=priority, table=0,
actions='resubmit(,%s)' % dest_table_id,
in_port=in_port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_install_drop(self):
priority = 99
in_port = 666
self.br.install_drop(priority=priority, in_port=in_port)
expected = [
call.add_flow(priority=priority, table=0,
actions='drop',
in_port=in_port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_install_normal(self):
priority = 99
in_port = 666
self.br.install_normal(priority=priority, in_port=in_port)
expected = [
call.add_flow(priority=priority, table=0,
actions='normal',
in_port=in_port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_dump_flows_for_table(self):
table = 23
with mock.patch.object(self.br, 'run_ofctl') as run_ofctl:
self.br.dump_flows(table)
run_ofctl.assert_has_calls([mock.call("dump-flows", mock.ANY)])
def test_dump_all_flows(self):
with mock.patch.object(self.br, 'run_ofctl') as run_ofctl:
self.br.dump_flows_all_tables()
run_ofctl.assert_has_calls([mock.call("dump-flows", [])])
class OVSDVRProcessTestMixin(object):
def test_install_dvr_process_ipv4(self):
vlan_tag = 999
gateway_ip = '192.0.2.1'
self.br.install_dvr_process_ipv4(vlan_tag=vlan_tag,
gateway_ip=gateway_ip)
expected = [
call.add_flow(table=self.dvr_process_table_id,
proto='arp', nw_dst=gateway_ip, actions='drop',
priority=3, dl_vlan=vlan_tag),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_delete_dvr_process_ipv4(self):
vlan_tag = 999
gateway_ip = '192.0.2.1'
self.br.delete_dvr_process_ipv4(vlan_tag=vlan_tag,
gateway_ip=gateway_ip)
expected = [
call.delete_flows(table=self.dvr_process_table_id,
dl_vlan=vlan_tag, proto='arp',
nw_dst=gateway_ip),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_install_dvr_process_ipv6(self):
vlan_tag = 999
gateway_mac = '08:60:6e:7f:74:e7'
self.br.install_dvr_process_ipv6(vlan_tag=vlan_tag,
gateway_mac=gateway_mac)
expected = [
call.add_flow(table=self.dvr_process_table_id,
proto='icmp6', dl_src=gateway_mac, actions='drop',
priority=3, dl_vlan=vlan_tag,
icmp_type=constants.ICMPV6_TYPE_RA),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_delete_dvr_process_ipv6(self):
vlan_tag = 999
gateway_mac = '08:60:6e:7f:74:e7'
self.br.delete_dvr_process_ipv6(vlan_tag=vlan_tag,
gateway_mac=gateway_mac)
expected = [
call.delete_flows(table=self.dvr_process_table_id,
dl_vlan=vlan_tag, dl_src=gateway_mac,
proto='icmp6',
icmp_type=constants.ICMPV6_TYPE_RA),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_install_dvr_process(self):
vlan_tag = 999
vif_mac = '00:0e:0c:5e:95:d0'
dvr_mac_address = 'f2:0b:a4:5b:b2:ab'
self.br.install_dvr_process(vlan_tag=vlan_tag,
vif_mac=vif_mac,
dvr_mac_address=dvr_mac_address)
expected = [
call.add_flow(priority=2, table=self.dvr_process_table_id,
dl_dst=vif_mac, dl_vlan=vlan_tag, actions='drop'),
call.add_flow(priority=1, table=self.dvr_process_table_id,
dl_vlan=vlan_tag, dl_src=vif_mac,
actions='mod_dl_src:%(mac)s,resubmit(,%(next)s)' % {
'mac': dvr_mac_address,
'next': self.dvr_process_next_table_id,
}),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_delete_dvr_process(self):
vlan_tag = 999
vif_mac = '00:0e:0c:5e:95:d0'
self.br.delete_dvr_process(vlan_tag=vlan_tag,
vif_mac=vif_mac)
expected = [
call.delete_flows(table=self.dvr_process_table_id,
dl_dst=vif_mac, dl_vlan=vlan_tag),
call.delete_flows(table=self.dvr_process_table_id,
dl_vlan=vlan_tag, dl_src=vif_mac),
]
self.assertEqual(expected, self.mock.mock_calls)

@ -1,260 +0,0 @@
# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
# Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from neutron_lib import constants as const
from neutron.tests.unit.plugins.ml2.drivers.openvswitch.agent.\
openflow.ovs_ofctl import ovs_bridge_test_base
call = mock.call # short hand
class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
def setUp(self):
super(OVSIntegrationBridgeTest, self).setUp()
self.setup_bridge_mock('br-int', self.br_int_cls)
def test_setup_default_table(self):
self.br.setup_default_table()
expected = [
call.add_flow(priority=0, table=23, actions='drop'),
call.add_flow(priority=0, table=0, actions='resubmit(,60)'),
call.add_flow(priority=3, table=60, actions='normal'),
call.add_flow(priority=0, table=24, actions='drop'),
call.add_flow(actions='drop', dl_vlan=4095,
priority=65535, table=0)
]
self.assertEqual(expected, self.mock.mock_calls)
def test_provision_local_vlan(self):
port = 999
lvid = 888
segmentation_id = 777
self.br.provision_local_vlan(port=port, lvid=lvid,
segmentation_id=segmentation_id)
expected = [
call.add_flow(priority=3, dl_vlan=segmentation_id,
in_port=port,
actions='mod_vlan_vid:%s,resubmit(,60)' % lvid),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_provision_local_vlan_novlan(self):
port = 999
lvid = 888
segmentation_id = None
self.br.provision_local_vlan(port=port, lvid=lvid,
segmentation_id=segmentation_id)
expected = [
call.add_flow(priority=3, dl_vlan=0xffff,
in_port=port,
actions='mod_vlan_vid:%s,resubmit(,60)' % lvid),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_reclaim_local_vlan(self):
port = 999
segmentation_id = 777
self.br.reclaim_local_vlan(port=port, segmentation_id=segmentation_id)
expected = [
call.delete_flows(dl_vlan=segmentation_id, in_port=port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_reclaim_local_vlan_novlan(self):
port = 999
segmentation_id = None
self.br.reclaim_local_vlan(port=port, segmentation_id=segmentation_id)
expected = [
call.delete_flows(dl_vlan=0xffff, in_port=port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_install_dvr_to_src_mac(self):
network_type = 'vxlan'
vlan_tag = 1111
gateway_mac = '08:60:6e:7f:74:e7'
dst_mac = '00:02:b3:13:fe:3d'
dst_port = 6666
self.br.install_dvr_to_src_mac(network_type=network_type,
vlan_tag=vlan_tag,
gateway_mac=gateway_mac,
dst_mac=dst_mac,
dst_port=dst_port)
expected = [
call.add_flow(priority=4, table=1, dl_dst=dst_mac,
dl_vlan=vlan_tag,
actions='mod_dl_src:%(mac)s,resubmit(,60)' % {
'mac': gateway_mac,
}),
call.add_flow(priority=4, table=60, dl_dst=dst_mac,
dl_vlan=vlan_tag,
actions='strip_vlan,output:%(port)s' % {
'port': dst_port,
}),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_delete_dvr_to_src_mac(self):
network_type = 'vxlan'
vlan_tag = 1111
dst_mac = '00:02:b3:13:fe:3d'
self.br.delete_dvr_to_src_mac(network_type=network_type,
vlan_tag=vlan_tag,
dst_mac=dst_mac)
expected = [
call.delete_flows(
strict=True, priority=4, table=1, dl_dst=dst_mac,
dl_vlan=vlan_tag),
call.delete_flows(
strict=True, priority=4, table=60, dl_dst=dst_mac,
dl_vlan=vlan_tag),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_install_dvr_to_src_mac_vlan(self):
network_type = 'vlan'
vlan_tag = 1111
gateway_mac = '08:60:6e:7f:74:e7'
dst_mac = '00:02:b3:13:fe:3d'
dst_port = 6666
self.br.install_dvr_to_src_mac(network_type=network_type,
vlan_tag=vlan_tag,
gateway_mac=gateway_mac,
dst_mac=dst_mac,
dst_port=dst_port)
expected = [
call.add_flow(priority=4, table=2, dl_dst=dst_mac,
dl_vlan=vlan_tag,
actions='mod_dl_src:%(mac)s,resubmit(,60)' % {
'mac': gateway_mac,
}),
call.add_flow(priority=4, table=60, dl_dst=dst_mac,
dl_vlan=vlan_tag,
actions='strip_vlan,output:%(port)s' % {
'port': dst_port,
}),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_delete_dvr_to_src_mac_vlan(self):
network_type = 'vlan'
vlan_tag = 1111
dst_mac = '00:02:b3:13:fe:3d'
self.br.delete_dvr_to_src_mac(network_type=network_type,
vlan_tag=vlan_tag,
dst_mac=dst_mac)
expected = [
call.delete_flows(
strict=True, priority=4, table=2, dl_dst=dst_mac,
dl_vlan=vlan_tag),
call.delete_flows(
strict=True, priority=4, table=60, dl_dst=dst_mac,
dl_vlan=vlan_tag),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_add_dvr_mac_vlan(self):
mac = '00:02:b3:13:fe:3d'
port = 8888
self.br.add_dvr_mac_vlan(mac=mac, port=port)
expected = [
call.add_flow(priority=4, table=0, actions='resubmit(,2)',
dl_src=mac, in_port=port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_remove_dvr_mac_vlan(self):
mac = '00:02:b3:13:fe:3d'
self.br.remove_dvr_mac_vlan(mac=mac)
expected = [
call.delete_flows(dl_src=mac, table=0),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_add_dvr_mac_tun(self):
mac = '00:02:b3:13:fe:3d'
port = 8888
self.br.add_dvr_mac_tun(mac=mac, port=port)
expected = [
call.add_flow(priority=2, table=0, actions='resubmit(,1)',
dl_src=mac, in_port=port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_remove_dvr_mac_tun(self):
mac = '00:02:b3:13:fe:3d'
port = 8888
self.br.remove_dvr_mac_tun(mac=mac, port=port)
expected = [
call.delete_flows(dl_src=mac, table=0, in_port=port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_install_icmpv6_na_spoofing_protection(self):
port = 8888
ip_addresses = ['2001:db8::1', 'fdf8:f53b:82e4::1/128']
self.br.install_icmpv6_na_spoofing_protection(port, ip_addresses)
expected = [
call.add_flow(dl_type=const.ETHERTYPE_IPV6,
actions='resubmit(,60)',
icmp_type=const.ICMPV6_TYPE_NA,
nw_proto=const.PROTO_NUM_IPV6_ICMP,
nd_target='2001:db8::1',
priority=2, table=24, in_port=8888),
call.add_flow(dl_type=const.ETHERTYPE_IPV6,
actions='resubmit(,60)',
icmp_type=const.ICMPV6_TYPE_NA,
nw_proto=const.PROTO_NUM_IPV6_ICMP,
nd_target='fdf8:f53b:82e4::1/128',
priority=2, table=24, in_port=8888),
call.add_flow(dl_type=const.ETHERTYPE_IPV6,
icmp_type=const.ICMPV6_TYPE_NA,
nw_proto=const.PROTO_NUM_IPV6_ICMP,
priority=10, table=0, in_port=8888,
actions='resubmit(,24)')
]
self.assertEqual(expected, self.mock.mock_calls)
def test_install_arp_spoofing_protection(self):
port = 8888
ip_addresses = ['192.0.2.1', '192.0.2.2/32']
self.br.install_arp_spoofing_protection(port, ip_addresses)
expected = [
call.add_flow(proto='arp', actions='resubmit(,25)',
arp_spa='192.0.2.1',
priority=2, table=24, in_port=8888),
call.add_flow(proto='arp', actions='resubmit(,25)',
arp_spa='192.0.2.2/32',
priority=2, table=24, in_port=8888),
call.add_flow(priority=10, table=0, in_port=8888,
actions='resubmit(,24)', proto='arp')
]
self.assertEqual(expected, self.mock.mock_calls)
def test_delete_arp_spoofing_protection(self):
port = 8888
self.br.delete_arp_spoofing_protection(port)
expected = [
call.delete_flows(table=0, in_port=8888, proto='arp'),
call.delete_flows(table=0, in_port=8888,
icmp_type=const.ICMPV6_TYPE_NA,
nw_proto=const.PROTO_NUM_IPV6_ICMP),
call.delete_flows(table=24, in_port=8888),
]
self.assertEqual(expected, self.mock.mock_calls)

@ -1,97 +0,0 @@
# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
# Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
import neutron.plugins.ml2.drivers.openvswitch.agent.common.constants \
as ovs_const
from neutron.tests.unit.plugins.ml2.drivers.openvswitch.agent.\
openflow.ovs_ofctl import ovs_bridge_test_base
call = mock.call # short hand
class OVSPhysicalBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
ovs_bridge_test_base.OVSDVRProcessTestMixin):
dvr_process_table_id = ovs_const.DVR_PROCESS_VLAN
dvr_process_next_table_id = ovs_const.LOCAL_VLAN_TRANSLATION
def setUp(self):
super(OVSPhysicalBridgeTest, self).setUp()
self.setup_bridge_mock('br-phys', self.br_phys_cls)
def test_setup_default_table(self):
self.br.setup_default_table()
expected = [
call.add_flow(priority=0, table=0, actions='normal'),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_provision_local_vlan(self):
port = 999
lvid = 888
segmentation_id = 777
distributed = False
self.br.provision_local_vlan(port=port, lvid=lvid,
segmentation_id=segmentation_id,
distributed=distributed)
expected = [
call.add_flow(priority=4, table=0, dl_vlan=lvid, in_port=port,
actions='mod_vlan_vid:%s,normal' % segmentation_id),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_provision_local_vlan_novlan(self):
port = 999
lvid = 888
segmentation_id = None
distributed = False
self.br.provision_local_vlan(port=port, lvid=lvid,
segmentation_id=segmentation_id,
distributed=distributed)
expected = [
call.add_flow(priority=4, table=0, dl_vlan=lvid, in_port=port,
actions='strip_vlan,normal')
]
self.assertEqual(expected, self.mock.mock_calls)
def test_reclaim_local_vlan(self):
port = 999
lvid = 888
self.br.reclaim_local_vlan(port=port, lvid=lvid)
expected = [
call.delete_flows(dl_vlan=lvid, in_port=port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_add_dvr_mac_vlan(self):
mac = '00:02:b3:13:fe:3d'
port = 8888
self.br.add_dvr_mac_vlan(mac=mac, port=port)
expected = [
call.add_flow(priority=2, table=3, dl_src=mac,
actions='output:%s' % port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_remove_dvr_mac_vlan(self):
mac = '00:02:b3:13:fe:3d'
self.br.remove_dvr_mac_vlan(mac=mac)
expected = [
call.delete_flows(dl_src=mac, table=3),
]
self.assertEqual(expected, self.mock.mock_calls)

@ -1,320 +0,0 @@
# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
# Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
import netaddr
import neutron.plugins.ml2.drivers.openvswitch.agent.common.constants \
as ovs_const
from neutron.tests.unit.plugins.ml2.drivers.openvswitch.agent.\
openflow.ovs_ofctl import ovs_bridge_test_base
call = mock.call # short hand
class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
ovs_bridge_test_base.OVSDVRProcessTestMixin):
dvr_process_table_id = ovs_const.DVR_PROCESS
dvr_process_next_table_id = ovs_const.PATCH_LV_TO_TUN
def setUp(self):
super(OVSTunnelBridgeTest, self).setUp()
self.setup_bridge_mock('br-tun', self.br_tun_cls)
self.stamp = self.br.default_cookie
def test_setup_default_table(self):
patch_int_ofport = 5555
mock_do_action_flows = mock.patch.object(self.br,
'do_action_flows').start()
self.mock.attach_mock(mock_do_action_flows, 'do_action_flows')
self.br.setup_default_table(patch_int_ofport=patch_int_ofport,
arp_responder_enabled=False)
flow_args = [{'priority': 1, 'in_port': patch_int_ofport,
'actions': 'resubmit(,2)'},
{'priority': 0, 'actions': 'drop'},
{'priority': 0, 'table': 2,
'dl_dst': '00:00:00:00:00:00/01:00:00:00:00:00',
'actions': 'resubmit(,20)'},
{'priority': 0, 'table': 2,
'dl_dst': '01:00:00:00:00:00/01:00:00:00:00:00',
'actions': 'resubmit(,22)'},
{'priority': 0, 'table': 3, 'actions': 'drop'},
{'priority': 0, 'table': 4, 'actions': 'drop'},
{'priority': 0, 'table': 6, 'actions': 'drop'},
{'priority': 1, 'table': 10,
'actions': 'learn(cookie=' + str(self.stamp) +
',table=20,priority=1,hard_timeout=300,'
'NXM_OF_VLAN_TCI[0..11],'
'NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],'
'load:0->NXM_OF_VLAN_TCI[],'
'load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],'
'output:NXM_OF_IN_PORT[]),'
'output:%s' % patch_int_ofport},
{'priority': 0, 'table': 20, 'actions': 'resubmit(,22)'}
]
expected = [call.do_action_flows('add', flow_args, False),
call.add_flow(priority=0, table=22, actions='drop')]
self.assertEqual(expected, self.mock.mock_calls)
def test_setup_default_table_arp_responder_enabled(self):
patch_int_ofport = 5555
mock_do_action_flows = mock.patch.object(self.br,
'do_action_flows').start()
self.mock.attach_mock(mock_do_action_flows, 'do_action_flows')
self.br.setup_default_table(patch_int_ofport=patch_int_ofport,
arp_responder_enabled=True)
flow_args = [{'priority': 1, 'in_port': patch_int_ofport,
'actions': 'resubmit(,2)'},
{'priority': 0, 'actions': 'drop'},
{'priority': 1, 'table': 2, 'dl_dst': 'ff:ff:ff:ff:ff:ff',
'actions': 'resubmit(,21)', 'proto': 'arp'},
{'priority': 0, 'table': 2,
'dl_dst': '00:00:00:00:00:00/01:00:00:00:00:00',
'actions': 'resubmit(,20)'},
{'priority': 0, 'table': 2,
'dl_dst': '01:00:00:00:00:00/01:00:00:00:00:00',
'actions': 'resubmit(,22)'},
{'priority': 0, 'table': 3, 'actions': 'drop'},
{'priority': 0, 'table': 4, 'actions': 'drop'},
{'priority': 0, 'table': 6, 'actions': 'drop'},
{'priority': 1, 'table': 10,
'actions': 'learn(cookie=' + str(self.stamp) +
',table=20,priority=1,hard_timeout=300,'
'NXM_OF_VLAN_TCI[0..11],'
'NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],'
'load:0->NXM_OF_VLAN_TCI[],'
'load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],'
'output:NXM_OF_IN_PORT[]),'
'output:%s' % patch_int_ofport},
{'priority': 0, 'table': 20, 'actions': 'resubmit(,22)'},
{'priority': 0, 'table': 21, 'actions': 'resubmit(,22)'}
]
expected = [call.do_action_flows('add', flow_args, False),
call.add_flow(priority=0, table=22, actions='drop')]
self.assertEqual(expected, self.mock.mock_calls)
def test_provision_local_vlan(self):
network_type = 'vxlan'
lvid = 888
segmentation_id = 777
distributed = False
self.br.provision_local_vlan(network_type=network_type, lvid=lvid,
segmentation_id=segmentation_id,
distributed=distributed)
expected = [
call.add_flow(priority=1, tun_id=segmentation_id,
actions='mod_vlan_vid:%s,resubmit(,10)' % lvid,
table=4),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_reclaim_local_vlan(self):
network_type = 'vxlan'
segmentation_id = 777
self.br.reclaim_local_vlan(network_type=network_type,
segmentation_id=segmentation_id)
expected = [
call.delete_flows(tun_id=segmentation_id, table=4),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_install_flood_to_tun(self):
vlan = 3333
tun_id = 2222
ports = [11, 44, 22, 33]
self.br.install_flood_to_tun(vlan=vlan,
tun_id=tun_id,
ports=ports)
expected = [
call.mod_flow(table=22, dl_vlan=vlan,
actions='strip_vlan,set_tunnel:%(tun)s,'
'output:%(ports)s' % {
'tun': tun_id,
'ports': ','.join(map(str, ports)),
}),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_delete_flood_to_tun(self):
vlan = 3333
self.br.delete_flood_to_tun(vlan=vlan)
expected = [
call.delete_flows(table=22, dl_vlan=vlan),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_install_unicast_to_tun(self):
vlan = 3333
port = 55
mac = '08:60:6e:7f:74:e7'
tun_id = 2222
self.br.install_unicast_to_tun(vlan=vlan,
tun_id=tun_id,
port=port,
mac=mac)
expected = [
call.add_flow(priority=2, table=20, dl_dst=mac, dl_vlan=vlan,
actions='strip_vlan,set_tunnel:%(tun)s,'
'output:%(port)s' % {
'tun': tun_id,
'port': port,
}),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_delete_unicast_to_tun(self):
vlan = 3333
mac = '08:60:6e:7f:74:e7'
self.br.delete_unicast_to_tun(vlan=vlan, mac=mac)
expected = [
call.delete_flows(table=20, dl_dst=mac, dl_vlan=vlan),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_delete_unicast_to_tun_without_mac(self):
vlan = 3333
mac = None
self.br.delete_unicast_to_tun(vlan=vlan, mac=mac)
expected = [
call.delete_flows(table=20, dl_vlan=vlan),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_install_arp_responder(self):
vlan = 3333
ip = '192.0.2.1'
mac = '08:60:6e:7f:74:e7'
self.br.install_arp_responder(vlan=vlan, ip=ip, mac=mac)
expected = [
call.add_flow(proto='arp', nw_dst=ip,
actions='move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],'
'mod_dl_src:%(mac)s,load:0x2->NXM_OF_ARP_OP[],'
'move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],'
'move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],'
'load:%(mac)#x->NXM_NX_ARP_SHA[],'
'load:%(ip)#x->NXM_OF_ARP_SPA[],in_port' % {
'mac': netaddr.EUI(mac,
dialect=netaddr.mac_unix),
'ip': netaddr.IPAddress(ip),
},
priority=1, table=21, dl_vlan=vlan),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_delete_arp_responder(self):
vlan = 3333
ip = '192.0.2.1'
self.br.delete_arp_responder(vlan=vlan, ip=ip)
expected = [
call.delete_flows(table=21, dl_vlan=vlan, proto='arp', nw_dst=ip),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_delete_arp_responder_without_ip(self):
vlan = 3333
ip = None
self.br.delete_arp_responder(vlan=vlan, ip=ip)
expected = [
call.delete_flows(table=21, dl_vlan=vlan, proto='arp'),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_setup_tunnel_port(self):
network_type = 'vxlan'
port = 11111
self.br.setup_tunnel_port(network_type=network_type, port=port)
expected = [
call.add_flow(priority=1, in_port=port, actions='resubmit(,4)'),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_cleanup_tunnel_port(self):
port = 11111
self.br.cleanup_tunnel_port(port=port)
expected = [
call.delete_flows(in_port=port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_add_dvr_mac_tun(self):
mac = '00:02:b3:13:fe:3d'
port = 8888
self.br.add_dvr_mac_tun(mac=mac, port=port)
expected = [
call.add_flow(priority=1, table=9, dl_src=mac,
actions='output:%s' % port),
]
self.assertEqual(expected, self.mock.mock_calls)
def test_remove_dvr_mac_tun(self):
mac = '00:02:b3:13:fe:3d'
self.br.remove_dvr_mac_tun(mac=mac)
expected = [
call.delete_flows(dl_src=mac, table=9),
]
self.assertEqual(expected, self.mock.mock_calls)
def _mock_add_tunnel_port(self, deferred_br=False):
port_name = 'fake_port'
remote_ip = '192.168.1.3'
local_ip = '192.168.1.2'
tunnel_type = 'vxlan'
vxlan_udp_port = '4789'
dont_fragment = True
if deferred_br:
with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.add_port',
return_value=9999) as add_port, \
self.br.deferred() as deferred_br:
ofport = deferred_br.add_tunnel_port(port_name, remote_ip,
local_ip, tunnel_type,
vxlan_udp_port,
dont_fragment)
else:
with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.add_port',
return_value=9999) as add_port:
ofport = self.br.add_tunnel_port(port_name, remote_ip,
local_ip, tunnel_type,
vxlan_udp_port,
dont_fragment)
self.assertEqual(9999, ofport)
self.assertEqual(1, add_port.call_count)
self.assertEqual(port_name, add_port.call_args[0][0])
def _mock_delete_port(self, deferred_br=False):
port_name = 'fake_port'
if deferred_br:
with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
'delete_port') as delete_port, \
self.br.deferred() as deferred_br:
deferred_br.delete_port(port_name)
else:
with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
'delete_port') as delete_port:
self.br.delete_port(port_name)
self.assertEqual([call(port_name)], delete_port.mock_calls)
def test_add_tunnel_port(self):
self._mock_add_tunnel_port()
def test_delete_port(self):
self._mock_delete_port()
def test_deferred_br_add_tunnel_port(self):
self._mock_add_tunnel_port(True)
def test_deferred_br_delete_port(self):
self._mock_delete_port(True)

@ -16,7 +16,7 @@
import mock
from neutron.agent.common import ovs_lib
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native \
import ovs_bridge
from neutron.tests import base
@ -29,7 +29,7 @@ class TestBRCookieOpenflow(base.BaseTestCase):
'neutron.agent.ovsdb.impl_idl._connection')
conn_patcher.start()
self.addCleanup(conn_patcher.stop)
self.br = ovs_bridge.OVSAgentBridge('br-int')
self.br = ovs_bridge.OVSAgentBridge('br-int', os_ken_app=mock.Mock())
def test_reserved_cookies(self):
def_cookie = self.br.default_cookie
@ -49,7 +49,7 @@ class TestBRCookieOpenflow(base.BaseTestCase):
self.assertNotIn(requested_cookie, self.br.reserved_cookies)
def test_set_agent_uuid_stamp(self):
self.br = ovs_bridge.OVSAgentBridge('br-int')
self.br = ovs_bridge.OVSAgentBridge('br-int', os_ken_app=mock.Mock())
def_cookie = self.br.default_cookie
new_cookie = ovs_lib.generate_random_cookie()
@ -60,7 +60,7 @@ class TestBRCookieOpenflow(base.BaseTestCase):
self.assertNotIn(def_cookie, self.br.reserved_cookies)
def test_set_agent_uuid_stamp_with_reserved_cookie(self):
self.br = ovs_bridge.OVSAgentBridge('br-int')
self.br = ovs_bridge.OVSAgentBridge('br-int', os_ken_app=mock.Mock())
def_cookie = self.br.default_cookie
new_cookie = self.br.request_cookie()

@ -38,33 +38,8 @@ class OVSAgentConfigTestBase(base.BaseTestCase):
self.mod_dvr_agent = importutils.import_module(_DVR_AGENT_NAME)
class OVSAgentTestBase(OVSAgentConfigTestBase):
def setUp(self):
super(OVSAgentTestBase, self).setUp()
conn_patcher = mock.patch(
'neutron.agent.ovsdb.impl_idl._connection')
conn_patcher.start()
self.addCleanup(conn_patcher.stop)
self.br_int_cls = importutils.import_class(self._BR_INT_CLASS)
self.br_phys_cls = importutils.import_class(self._BR_PHYS_CLASS)
self.br_tun_cls = importutils.import_class(self._BR_TUN_CLASS)
class OVSOSKenTestBase(OVSAgentConfigTestBase):
def _bridge_classes(self):
return {
'br_int': self.br_int_cls,
'br_phys': self.br_phys_cls,
'br_tun': self.br_tun_cls,
}
class OVSOFCtlTestBase(OVSAgentTestBase):
_DRIVER_PACKAGE = _AGENT_PACKAGE + '.openflow.ovs_ofctl'
_BR_INT_CLASS = _DRIVER_PACKAGE + '.br_int.OVSIntegrationBridge'
_BR_TUN_CLASS = _DRIVER_PACKAGE + '.br_tun.OVSTunnelBridge'
_BR_PHYS_CLASS = _DRIVER_PACKAGE + '.br_phys.OVSPhysicalBridge'
class OVSOSKenTestBase(OVSAgentTestBase):
_DRIVER_PACKAGE = _AGENT_PACKAGE + '.openflow.native'
_BR_INT_CLASS = _DRIVER_PACKAGE + '.br_int.OVSIntegrationBridge'
_BR_TUN_CLASS = _DRIVER_PACKAGE + '.br_tun.OVSTunnelBridge'
@ -75,6 +50,13 @@ class OVSOSKenTestBase(OVSAgentTestBase):
self.fake_oflib_of.start()
self.addCleanup(self.fake_oflib_of.stop)
super(OVSOSKenTestBase, self).setUp()
conn_patcher = mock.patch(
'neutron.agent.ovsdb.impl_idl._connection')
conn_patcher.start()
self.addCleanup(conn_patcher.stop)
self.br_int_cls = importutils.import_class(self._BR_INT_CLASS)
self.br_phys_cls = importutils.import_class(self._BR_PHYS_CLASS)
self.br_tun_cls = importutils.import_class(self._BR_TUN_CLASS)
os_ken_app = mock.Mock()
self.br_int_cls = functools.partial(self.br_int_cls,
os_ken_app=os_ken_app)
@ -82,3 +64,10 @@ class OVSOSKenTestBase(OVSAgentTestBase):
os_ken_app=os_ken_app)
self.br_tun_cls = functools.partial(self.br_tun_cls,
os_ken_app=os_ken_app)
def _bridge_classes(self):
return {
'br_int': self.br_int_cls,
'br_phys': self.br_phys_cls,
'br_tun': self.br_tun_cls,
}

@ -26,7 +26,7 @@ from neutron.tests.unit.plugins.ml2.drivers.openvswitch.agent \
import ovs_test_base
class TestOVSAgentExtensionAPI(ovs_test_base.OVSOFCtlTestBase):
class TestOVSAgentExtensionAPI(ovs_test_base.OVSOSKenTestBase):
def setUp(self):
super(TestOVSAgentExtensionAPI, self).setUp()
@ -69,121 +69,6 @@ class TestOVSAgentExtensionAPI(ovs_test_base.OVSOFCtlTestBase):
self._test_bridge(self.br_phys[phys_br.br_name], phys_br)
class TestOVSCookieBridgeOFCtl(ovs_test_base.OVSOFCtlTestBase):
def setUp(self):
super(TestOVSCookieBridgeOFCtl, self).setUp()
self.bridge = self.br_int_cls("br-int")
mock.patch.object(self.bridge, "run_ofctl").start()
self.tested_bridge = ovs_ext_agt.OVSCookieBridge(self.bridge)
# mocking do_action_flows does not work, because this method is
# later wrapped by the cookie bridge code, and six.wraps apparently
# can't wrap a mock, so we mock deeper
self.mock_build_flow_expr_str = mock.patch(
'neutron.agent.common.ovs_lib._build_flow_expr_str',
return_value="").start()
def test_cookie(self):
self.assertNotEqual(self.bridge._default_cookie,
self.tested_bridge._default_cookie)
def test_reserved(self):
self.assertIn(self.tested_bridge._default_cookie,
self.bridge.reserved_cookies)
def assert_mock_build_flow_expr_str_call(self, action, kwargs_list,
strict=False):
self.mock_build_flow_expr_str.assert_called_once_with(
kwargs_list[0],
action,
strict
)
def test_add_flow_without_cookie(self):
self.tested_bridge.add_flow(in_port=1, actions="output:2")
self.assert_mock_build_flow_expr_str_call(
'add',
[{"in_port": 1,
"actions": "output:2",
"cookie": self.tested_bridge._default_cookie}]
)
def test_mod_flow_without_cookie(self):
self.tested_bridge.mod_flow(in_port=1, actions="output:2")
self.assert_mock_build_flow_expr_str_call(
'mod',
[{"in_port": 1,
"actions": "output:2",
"cookie": self.tested_bridge._default_cookie}]
)
def test_del_flows_without_cookie(self):
self.tested_bridge.delete_flows(in_port=1)
self.assert_mock_build_flow_expr_str_call(
'del',
[{"in_port": 1,
"cookie": str(self.tested_bridge._default_cookie) + '/-1'}]
)
def test_add_flow_with_cookie(self):
self.tested_bridge.add_flow(cookie=1234,
in_port=1, actions="output:2")
self.assert_mock_build_flow_expr_str_call(
'add',
[{"in_port": 1,
"actions": "output:2",
"cookie": 1234}]
)
def test_mod_flow_with_cookie(self):
self.tested_bridge.mod_flow(cookie='1234',
in_port=1, actions="output:2")
self.assert_mock_build_flow_expr_str_call(
'mod',
[{"in_port": 1,
"actions": "output:2",
"cookie": "1234"}]
)
def test_del_flows_with_cookie(self):
self.tested_bridge.delete_flows(cookie=1234, in_port=1)
self.assert_mock_build_flow_expr_str_call(
'del',
[{"in_port": 1,
"cookie": "1234/-1"}]
)
def test_mod_flow_with_cookie_mask(self):
self.tested_bridge.mod_flow(cookie='1234/3',
in_port=1, actions="output:2")
self.assert_mock_build_flow_expr_str_call(
'mod',
[{"in_port": 1,
"actions": "output:2",
"cookie": str(1234) + '/3'}]
)
def test_del_flows_with_cookie_mask(self):
self.tested_bridge.delete_flows(cookie='1234/7', in_port=1)
self.assert_mock_build_flow_expr_str_call(
'del',
[{"in_port": 1,
"cookie": str(1234) + '/7'}]
)
def test_install_drop(self):
self.tested_bridge.install_drop()
self.assert_mock_build_flow_expr_str_call(
'add',
[{"table": 0,
"priority": 0,
"actions": "drop",
"cookie": self.tested_bridge._default_cookie}]
)
class TestOVSCookieBridgeOSKen(native_ovs_bridge_test_base.OVSBridgeTestBase):
def setUp(self):

@ -2422,31 +2422,8 @@ class TestOvsNeutronAgent(object):
mock_update_segid.assert_not_called()
class TestOvsNeutronAgentOFCtl(TestOvsNeutronAgent,
ovs_test_base.OVSOFCtlTestBase):
def test_cleanup_stale_flows(self):
with mock.patch.object(self.agent.int_br,
'dump_flows_all_tables') as dump_flows,\
mock.patch.object(self.agent.int_br,
'delete_flows') as del_flow:
self.agent.int_br.set_agent_uuid_stamp(1234)
dump_flows.return_value = [
'cookie=0x4d2, duration=50.156s, table=0,actions=drop',
'cookie=0x4321, duration=54.143s, table=2, priority=0',
'cookie=0x2345, duration=50.125s, table=2, priority=0',
'cookie=0x4d2, duration=52.112s, table=3, actions=drop',
]
self.agent.iter_num = 3
self.agent.cleanup_stale_flows()
expected = [
mock.call(cookie='0x4321/-1', table='2'),
mock.call(cookie='0x2345/-1', table='2'),
]
self.assertEqual(expected, del_flow.mock_calls)
class TestOvsNeutronAgentOSKen(TestOvsNeutronAgent,
ovs_test_base.OVSOSKenTestBase):
ovs_test_base.OVSOSKenTestBase):
def test_cleanup_stale_flows(self):
uint64_max = (1 << 64) - 1
with mock.patch.object(self.agent.int_br,
@ -2600,11 +2577,6 @@ class AncillaryBridgesTest(object):
self.assertEqual(expected, actual)
class AncillaryBridgesTestOFCtl(AncillaryBridgesTest,
ovs_test_base.OVSOFCtlTestBase):
pass
class AncillaryBridgesTestOSKen(AncillaryBridgesTest,
ovs_test_base.OVSOSKenTestBase):
pass
@ -3614,11 +3586,6 @@ class TestOvsDvrNeutronAgent(object):
self._test_scan_ports_failure('scan_ancillary_ports')
class TestOvsDvrNeutronAgentOFCtl(TestOvsDvrNeutronAgent,
ovs_test_base.OVSOFCtlTestBase):
pass
class TestOvsDvrNeutronAgentOSKen(TestOvsDvrNeutronAgent,
ovs_test_base.OVSOSKenTestBase):
pass

@ -648,10 +648,6 @@ class TunnelTest(object):
self._verify_mock_calls()
class TunnelTestOFCtl(TunnelTest, ovs_test_base.OVSOFCtlTestBase):
pass
class TunnelTestOSKen(TunnelTest, ovs_test_base.OVSOSKenTestBase):
pass
@ -745,11 +741,6 @@ class TunnelTestUseVethInterco(TunnelTest):
'--timeout=10'])]
class TunnelTestUseVethIntercoOFCtl(TunnelTestUseVethInterco,
ovs_test_base.OVSOFCtlTestBase):
pass
class TunnelTestUseVethIntercoOSKen(TunnelTestUseVethInterco,
ovs_test_base.OVSOSKenTestBase):
pass
@ -764,11 +755,6 @@ class TunnelTestWithMTU(TunnelTestUseVethInterco):
self.intb_expected.append(mock.call.link.set_mtu(self.VETH_MTU))
class TunnelTestWithMTUOFCtl(TunnelTestWithMTU,
ovs_test_base.OVSOFCtlTestBase):
pass
class TunnelTestWithMTUOSKen(TunnelTestWithMTU,
ovs_test_base.OVSOSKenTestBase):
pass

@ -24,7 +24,7 @@ from neutron.api.rpc.handlers import resources_rpc
from neutron.plugins.ml2.drivers.openvswitch.agent import (
ovs_agent_extension_api as ovs_ext_api)
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl import (
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native import (
ovs_bridge)
from neutron.services.logapi.agent import log_extension as log_ext
from neutron.tests import base
@ -54,10 +54,12 @@ class LoggingExtensionBaseTestCase(base.BaseTestCase):
self.agent_ext = log_ext.LoggingExtension()
self.context = context.get_admin_context()
self.connection = mock.Mock()
os_ken_app = mock.Mock()
agent_api = ovs_ext_api.OVSAgentExtensionAPI(
ovs_bridge.OVSAgentBridge('br-int'),
ovs_bridge.OVSAgentBridge('br-tun'),
{'physnet1': ovs_bridge.OVSAgentBridge('br-physnet1')})
ovs_bridge.OVSAgentBridge('br-int', os_ken_app=os_ken_app),
ovs_bridge.OVSAgentBridge('br-tun', os_ken_app=os_ken_app),
{'physnet1': ovs_bridge.OVSAgentBridge(
'br-physnet1', os_ken_app=os_ken_app)})
self.agent_ext.consume_api(agent_api)
mock.patch(
'neutron.manager.NeutronManager.load_class_for_provider').start()

@ -0,0 +1,9 @@
---
upgrade:
- |
The deprecated ``of_interface`` option is removed. Neutron will
always use the ``native`` driver, which has been the default
since Pike (11.0).
If old driver ``ovs-ofctl`` was used before upgrade, automatically
done change to ``native`` driver will cause short break of data plane
connectivity during neutron-ovs-agent upgrade.