This is a preparation to introduce another Ryu-based implementation.
The aim is to replace this with the new Ryu-based implementation
eventually.
Add a config option for OVS-agent which selects the implementation.
Currently, the only available choice is 'ovs-ofctl'.
Also, this commit simplifies DVR logics by reducing duplications
and makes some of DVR UTs actually check the flows rather than just
"add_flow is called".
Partially-Implements: blueprint ovs-ofctl-to-python
Change-Id: Ie1224f8a1c17268cd7d1c474ed82fdfb8852eaa8
# ovs-vsctl set-manager ptcp:6640:127.0.0.1
# ovsdb_connection = tcp:127.0.0.1:6640
+# (StrOpt) OpenFlow interface to use.
+# 'ovs-ofctl' is currently the only available choice.
+# of_interface = ovs-ofctl
+
[agent]
# Agent's polling interval in seconds
# polling_interval = 2
# License for the specific language governing permissions and limitations
# under the License.
-from neutron.plugins.openvswitch.agent import ovs_neutron_agent
+import neutron.plugins.openvswitch.agent.main as agent_main
def main():
- ovs_neutron_agent.main()
+ agent_main.main()
--- /dev/null
+# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
+# Copyright (C) 2014 Fumihiko Kakuma <kakuma at valinux co jp>
+# 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 sys
+
+from oslo_config import cfg
+from oslo_log import log as logging
+from oslo_utils import importutils
+
+from neutron.common import config as common_config
+from neutron.common import utils as n_utils
+
+
+LOG = logging.getLogger(__name__)
+cfg.CONF.import_group('OVS', 'neutron.plugins.openvswitch.common.config')
+
+
+_main_modules = {
+ 'ovs-ofctl': 'neutron.plugins.openvswitch.agent.openflow.ovs_ofctl.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()
+ common_config.setup_logging()
+ n_utils.log_opt_values(LOG)
+ mod.main()
--- /dev/null
+# 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.
+
+
+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',
+ 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',
+ 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)
--- /dev/null
+# 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
+"""
+
+from neutron.plugins.common import constants as p_const
+from neutron.plugins.openvswitch.agent.openflow.ovs_ofctl import ovs_bridge
+from neutron.plugins.openvswitch.common import constants
+
+
+class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge):
+ """openvswitch agent br-int specific logic."""
+
+ def setup_default_table(self):
+ self.delete_flows()
+ self.install_normal()
+ self.setup_canary_table()
+ self.install_drop(table_id=constants.ARP_SPOOF_TABLE)
+
+ 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,normal" % lvid)
+
+ 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 == p_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="strip_vlan,mod_dl_src:%s,"
+ "output:%s" % (gateway_mac, 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)
+ self.delete_flows(table=table_id,
+ 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_id=constants.LOCAL_SWITCHING,
+ eth_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_id=constants.LOCAL_SWITCHING,
+ in_port=port, eth_src=mac)
+
+ 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.install_normal(
+ table_id=constants.ARP_SPOOF_TABLE, priority=2,
+ proto='arp', arp_spa=ip, in_port=port)
+
+ # 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_id=constants.LOCAL_SWITCHING,
+ in_port=port, proto='arp')
+ self.delete_flows(table_id=constants.ARP_SPOOF_TABLE,
+ in_port=port)
--- /dev/null
+# 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.openvswitch.agent.openflow.ovs_ofctl import br_dvr_process
+from neutron.plugins.openvswitch.agent.openflow.ovs_ofctl import ovs_bridge
+from neutron.plugins.openvswitch.common import constants
+
+
+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.delete_flows()
+ 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_id=constants.DVR_NOT_LEARN_VLAN,
+ eth_src=mac)
--- /dev/null
+# 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.openvswitch.agent.openflow.ovs_ofctl import br_dvr_process
+from neutron.plugins.openvswitch.agent.openflow.ovs_ofctl import ovs_bridge
+from neutron.plugins.openvswitch.common import constants
+
+
+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
+ self.add_flow(priority=1,
+ in_port=patch_int_ofport,
+ actions="resubmit(,%s)" %
+ constants.PATCH_LV_TO_TUN)
+ self.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): arp_op=arp.ARP_REQUEST
+ self.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
+ self.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
+ self.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:
+ self.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 = ("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[]" %
+ constants.UCAST_TO_TUN)
+ # Once remote mac addresses are learnt, output packet to patch_int
+ self.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
+ self.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
+ self.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):
+ self.add_flow(priority=1,
+ in_port=port,
+ actions="resubmit(,%s)" %
+ constants.TUN_TABLE[network_type])
+
+ def cleanup_tunnel_port(self, port):
+ self.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_id=constants.DVR_NOT_LEARN,
+ eth_src=mac)
+
+ def deferred(self, **kwargs):
+ return DeferredOVSTunnelBridge(self, **kwargs)
+
+
+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',
+ ]
+
+ def __getattr__(self, name):
+ if name in self._METHODS:
+ m = getattr(self.br, name)
+ return functools.partial(m, deferred_br=self)
+ raise AttributeError(name)
--- /dev/null
+# 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.openvswitch.agent.openflow.ovs_ofctl import br_int
+from neutron.plugins.openvswitch.agent.openflow.ovs_ofctl import br_phys
+from neutron.plugins.openvswitch.agent.openflow.ovs_ofctl import br_tun
+from neutron.plugins.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)
--- /dev/null
+# 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.
+
+# Field name mappings (from Ryu 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 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 delete_flows(self, **kwargs):
+ # NOTE(yamamoto): super() points to ovs_lib.OVSBridge.
+ # See ovs_bridge.py how this class is actually used.
+ if kwargs:
+ super(OpenFlowSwitchMixin, self).delete_flows(
+ **self._conv_args(kwargs))
+ else:
+ super(OpenFlowSwitchMixin, self).remove_all_flows()
--- /dev/null
+# 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.openvswitch.agent.openflow.ovs_ofctl import ofswitch
+
+
+class OVSAgentBridge(ofswitch.OpenFlowSwitchMixin, ovs_lib.OVSBridge):
+ """Common code for bridges used by OVS agent"""
+
+ def setup_controllers(self, conf):
+ self.set_protocols("[OpenFlow10]")
+ self.del_controller()
+
+ def drop_port(self, in_port):
+ self.install_drop(priority=2, in_port=in_port)
if not self.in_distributed_mode():
# switch all traffic using L2 learning
- self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
- priority=1, actions="normal")
+ # REVISIT(yamamoto): why to install the same flow as
+ # setup_integration_br?
+ self.int_br.install_normal()
def get_dvr_mac_address_with_retry(self):
# Get the local DVR MAC Address from the Neutron Server.
LOG.info(_LI("L2 Agent operating in DVR Mode with MAC %s"),
self.dvr_mac_address)
# Remove existing flows in integration bridge
- self.int_br.remove_all_flows()
+ self.int_br.delete_flows()
# Add a canary flow to int_br to track OVS restarts
- self.int_br.add_flow(table=constants.CANARY_TABLE, priority=0,
- actions="drop")
+ self.int_br.setup_canary_table()
# Insert 'drop' action as the default for Table DVR_TO_SRC_MAC
- self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC,
- priority=1,
- actions="drop")
+ self.int_br.install_drop(table_id=constants.DVR_TO_SRC_MAC, priority=1)
- self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC_VLAN,
- priority=1,
- actions="drop")
+ self.int_br.install_drop(table_id=constants.DVR_TO_SRC_MAC_VLAN,
+ priority=1)
# Insert 'normal' action as the default for Table LOCAL_SWITCHING
- self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
- priority=1,
- actions="normal")
+ self.int_br.install_normal(table_id=constants.LOCAL_SWITCHING,
+ priority=1)
for physical_network in self.bridge_mappings:
- self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
- priority=2,
- in_port=self.int_ofports[physical_network],
- actions="drop")
+ self.int_br.install_drop(table_id=constants.LOCAL_SWITCHING,
+ priority=2,
+ in_port=self.int_ofports[
+ physical_network])
def setup_dvr_flows_on_tun_br(self):
'''Setup up initial dvr flows into br-tun'''
if not self.enable_tunneling or not self.in_distributed_mode():
return
- self.tun_br.add_flow(priority=1,
- in_port=self.patch_int_ofport,
- actions="resubmit(,%s)" %
- constants.DVR_PROCESS)
+ self.tun_br.install_goto(dest_table_id=constants.DVR_PROCESS,
+ priority=1,
+ in_port=self.patch_int_ofport)
# table-miss should be sent to learning table
- self.tun_br.add_flow(table=constants.DVR_NOT_LEARN,
- priority=0,
- actions="resubmit(,%s)" %
- constants.LEARN_FROM_TUN)
+ self.tun_br.install_goto(table_id=constants.DVR_NOT_LEARN,
+ dest_table_id=constants.LEARN_FROM_TUN)
- self.tun_br.add_flow(table=constants.DVR_PROCESS,
- priority=0,
- actions="resubmit(,%s)" %
- constants.PATCH_LV_TO_TUN)
+ self.tun_br.install_goto(table_id=constants.DVR_PROCESS,
+ dest_table_id=constants.PATCH_LV_TO_TUN)
def setup_dvr_flows_on_phys_br(self):
'''Setup up initial dvr flows into br-phys'''
return
for physical_network in self.bridge_mappings:
- self.phys_brs[physical_network].add_flow(priority=2,
+ self.phys_brs[physical_network].install_goto(
in_port=self.phys_ofports[physical_network],
- actions="resubmit(,%s)" %
- constants.DVR_PROCESS_VLAN)
- self.phys_brs[physical_network].add_flow(priority=1,
- actions="resubmit(,%s)" %
- constants.DVR_NOT_LEARN_VLAN)
- self.phys_brs[physical_network].add_flow(
- table=constants.DVR_PROCESS_VLAN,
- priority=0,
- actions="resubmit(,%s)" %
- constants.LOCAL_VLAN_TRANSLATION)
- self.phys_brs[physical_network].add_flow(
- table=constants.LOCAL_VLAN_TRANSLATION,
priority=2,
- in_port=self.phys_ofports[physical_network],
- actions="drop")
- self.phys_brs[physical_network].add_flow(
- table=constants.DVR_NOT_LEARN_VLAN,
+ dest_table_id=constants.DVR_PROCESS_VLAN)
+ self.phys_brs[physical_network].install_goto(
priority=1,
- actions="NORMAL")
+ dest_table_id=constants.DVR_NOT_LEARN_VLAN)
+ self.phys_brs[physical_network].install_goto(
+ table_id=constants.DVR_PROCESS_VLAN,
+ priority=0,
+ dest_table_id=constants.LOCAL_VLAN_TRANSLATION)
+ self.phys_brs[physical_network].install_drop(
+ table_id=constants.LOCAL_VLAN_TRANSLATION,
+ in_port=self.phys_ofports[physical_network],
+ priority=2)
+ self.phys_brs[physical_network].install_normal(
+ table_id=constants.DVR_NOT_LEARN_VLAN,
+ priority=1)
+
+ def _add_dvr_mac_for_phys_br(self, physical_network, mac):
+ self.int_br.add_dvr_mac_vlan(mac=mac,
+ port=self.int_ofports[physical_network])
+ phys_br = self.phys_brs[physical_network]
+ phys_br.add_dvr_mac_vlan(mac=mac,
+ port=self.phys_ofports[physical_network])
+
+ def _remove_dvr_mac_for_phys_br(self, physical_network, mac):
+ # REVISIT(yamamoto): match in_port as well?
+ self.int_br.remove_dvr_mac_vlan(mac=mac)
+ phys_br = self.phys_brs[physical_network]
+ # REVISIT(yamamoto): match in_port as well?
+ phys_br.remove_dvr_mac_vlan(mac=mac)
+
+ def _add_dvr_mac_for_tun_br(self, mac):
+ self.int_br.add_dvr_mac_tun(mac=mac, port=self.patch_tun_ofport)
+ self.tun_br.add_dvr_mac_tun(mac=mac, port=self.patch_int_ofport)
+
+ def _remove_dvr_mac_for_tun_br(self, mac):
+ self.int_br.remove_dvr_mac_tun(mac=mac, port=self.patch_tun_ofport)
+ # REVISIT(yamamoto): match in_port as well?
+ self.tun_br.remove_dvr_mac_tun(mac=mac)
+
+ def _add_dvr_mac(self, mac):
+ for physical_network in self.bridge_mappings:
+ self._add_dvr_mac_for_phys_br(physical_network, mac)
+ if self.enable_tunneling:
+ self._add_dvr_mac_for_tun_br(mac)
+ LOG.debug("Added DVR MAC flow for %s", mac)
+ self.registered_dvr_macs.add(mac)
+
+ def _remove_dvr_mac(self, mac):
+ for physical_network in self.bridge_mappings:
+ self._remove_dvr_mac_for_phys_br(physical_network, mac)
+ if self.enable_tunneling:
+ self._remove_dvr_mac_for_tun_br(mac)
+ LOG.debug("Removed DVR MAC flow for %s", mac)
+ self.registered_dvr_macs.remove(mac)
def setup_dvr_mac_flows_on_all_brs(self):
if not self.in_distributed_mode():
for mac in dvr_macs:
if mac['mac_address'] == self.dvr_mac_address:
continue
- for physical_network in self.bridge_mappings:
- self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
- priority=4,
- in_port=self.int_ofports[physical_network],
- dl_src=mac['mac_address'],
- actions="resubmit(,%s)" %
- constants.DVR_TO_SRC_MAC_VLAN)
- self.phys_brs[physical_network].add_flow(
- table=constants.DVR_NOT_LEARN_VLAN,
- priority=2,
- dl_src=mac['mac_address'],
- actions="output:%s" %
- self.phys_ofports[physical_network])
-
- if self.enable_tunneling:
- # Table 0 (default) will now sort DVR traffic from other
- # traffic depending on in_port
- self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
- priority=2,
- in_port=self.patch_tun_ofport,
- dl_src=mac['mac_address'],
- actions="resubmit(,%s)" %
- constants.DVR_TO_SRC_MAC)
- # Table DVR_NOT_LEARN ensures unique dvr macs in the cloud
- # are not learnt, as they may
- # result in flow explosions
- self.tun_br.add_flow(table=constants.DVR_NOT_LEARN,
- priority=1,
- dl_src=mac['mac_address'],
- actions="output:%s" %
- self.patch_int_ofport)
- self.registered_dvr_macs.add(mac['mac_address'])
+ self._add_dvr_mac(mac['mac_address'])
def dvr_mac_address_update(self, dvr_macs):
if not self.dvr_mac_address:
dvr_macs_removed = self.registered_dvr_macs - dvr_host_macs
for oldmac in dvr_macs_removed:
- for physical_network in self.bridge_mappings:
- self.int_br.delete_flows(table=constants.LOCAL_SWITCHING,
- in_port=self.int_ofports[physical_network],
- dl_src=oldmac)
- self.phys_brs[physical_network].delete_flows(
- table=constants.DVR_NOT_LEARN_VLAN,
- dl_src=oldmac)
- if self.enable_tunneling:
- self.int_br.delete_flows(table=constants.LOCAL_SWITCHING,
- in_port=self.patch_tun_ofport,
- dl_src=oldmac)
- self.tun_br.delete_flows(table=constants.DVR_NOT_LEARN,
- dl_src=oldmac)
- LOG.debug("Removed DVR MAC flow for %s", oldmac)
- self.registered_dvr_macs.remove(oldmac)
+ self._remove_dvr_mac(oldmac)
for newmac in dvr_macs_added:
- for physical_network in self.bridge_mappings:
- self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
- priority=4,
- in_port=self.int_ofports[physical_network],
- dl_src=newmac,
- actions="resubmit(,%s)" %
- constants.DVR_TO_SRC_MAC_VLAN)
- self.phys_brs[physical_network].add_flow(
- table=constants.DVR_NOT_LEARN_VLAN,
- priority=2,
- dl_src=newmac,
- actions="output:%s" %
- self.phys_ofports[physical_network])
- if self.enable_tunneling:
- self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
- priority=2,
- in_port=self.patch_tun_ofport,
- dl_src=newmac,
- actions="resubmit(,%s)" %
- constants.DVR_TO_SRC_MAC)
- self.tun_br.add_flow(table=constants.DVR_NOT_LEARN,
- priority=1,
- dl_src=newmac,
- actions="output:%s" %
- self.patch_int_ofport)
- LOG.debug("Added DVR MAC flow for %s", newmac)
- self.registered_dvr_macs.add(newmac)
+ self._add_dvr_mac(newmac)
def in_distributed_mode(self):
return self.dvr_mac_address is not None
return device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE
def process_tunneled_network(self, network_type, lvid, segmentation_id):
- if self.in_distributed_mode():
- table_id = constants.DVR_NOT_LEARN
- else:
- table_id = constants.LEARN_FROM_TUN
- self.tun_br.add_flow(table=constants.TUN_TABLE[network_type],
- priority=1,
- tun_id=segmentation_id,
- actions="mod_vlan_vid:%s,"
- "resubmit(,%s)" %
- (lvid, table_id))
+ self.tun_br.provision_local_vlan(
+ network_type=network_type,
+ lvid=lvid,
+ segmentation_id=segmentation_id,
+ distributed=self.in_distributed_mode())
def _bind_distributed_router_interface_port(self, port, lvm,
fixed_ips, device_owner):
# DVR takes over
ldm.set_dvr_owned(True)
- table_id = constants.DVR_TO_SRC_MAC
vlan_to_use = lvm.vlan
if lvm.network_type == p_const.TYPE_VLAN:
- table_id = constants.DVR_TO_SRC_MAC_VLAN
vlan_to_use = lvm.segmentation_id
subnet_info = ldm.get_subnet_info()
comp_ovsport.add_subnet(subnet_uuid)
self.local_ports[vif.vif_id] = comp_ovsport
# create rule for just this vm port
- self.int_br.add_flow(table=table_id,
- priority=4,
- dl_vlan=vlan_to_use,
- dl_dst=comp_ovsport.get_mac(),
- actions="strip_vlan,mod_dl_src:%s,"
- "output:%s" %
- (subnet_info['gateway_mac'],
- comp_ovsport.get_ofport()))
+ self.int_br.install_dvr_to_src_mac(
+ network_type=lvm.network_type,
+ vlan_tag=vlan_to_use,
+ gateway_mac=subnet_info['gateway_mac'],
+ dst_mac=comp_ovsport.get_mac(),
+ dst_port=comp_ovsport.get_ofport())
if lvm.network_type == p_const.TYPE_VLAN:
- args = {'table': constants.DVR_PROCESS_VLAN,
- 'priority': 3,
- 'dl_vlan': lvm.vlan,
- 'actions': "drop"}
- if ip_version == 4:
- args['proto'] = 'arp'
- args['nw_dst'] = subnet_info['gateway_ip']
- else:
- args['proto'] = 'icmp6'
- args['icmp_type'] = n_const.ICMPV6_TYPE_RA
- args['dl_src'] = subnet_info['gateway_mac']
- # TODO(vivek) remove the IPv6 related add_flow once SNAT is not
+ # TODO(vivek) remove the IPv6 related flows once SNAT is not
# used for IPv6 DVR.
- self.phys_brs[lvm.physical_network].add_flow(**args)
- self.phys_brs[lvm.physical_network].add_flow(
- table=constants.DVR_PROCESS_VLAN,
- priority=2,
- dl_vlan=lvm.vlan,
- dl_dst=port.vif_mac,
- actions="drop")
-
- self.phys_brs[lvm.physical_network].add_flow(
- table=constants.DVR_PROCESS_VLAN,
- priority=1,
- dl_vlan=lvm.vlan,
- dl_src=port.vif_mac,
- actions="mod_dl_src:%s,resubmit(,%s)" %
- (self.dvr_mac_address, constants.LOCAL_VLAN_TRANSLATION))
-
+ br = self.phys_brs[lvm.physical_network]
if lvm.network_type in constants.TUNNEL_NETWORK_TYPES:
- args = {'table': constants.DVR_PROCESS,
- 'priority': 3,
- 'dl_vlan': lvm.vlan,
- 'actions': "drop"}
- if ip_version == 4:
- args['proto'] = 'arp'
- args['nw_dst'] = subnet_info['gateway_ip']
- else:
- args['proto'] = 'icmp6'
- args['icmp_type'] = n_const.ICMPV6_TYPE_RA
- args['dl_src'] = subnet_info['gateway_mac']
- # TODO(vivek) remove the IPv6 related add_flow once SNAT is not
- # used for IPv6 DVR.
- self.tun_br.add_flow(**args)
- self.tun_br.add_flow(table=constants.DVR_PROCESS,
- priority=2,
- dl_vlan=lvm.vlan,
- dl_dst=port.vif_mac,
- actions="drop")
-
- self.tun_br.add_flow(table=constants.DVR_PROCESS,
- priority=1,
- dl_vlan=lvm.vlan,
- dl_src=port.vif_mac,
- actions="mod_dl_src:%s,resubmit(,%s)" %
- (self.dvr_mac_address,
- constants.PATCH_LV_TO_TUN))
+ br = self.tun_br
+ # TODO(vivek) remove the IPv6 related flows once SNAT is not
+ # used for IPv6 DVR.
+ if ip_version == 4:
+ br.install_dvr_process_ipv4(
+ vlan_tag=lvm.vlan, gateway_ip=subnet_info['gateway_ip'])
+ else:
+ br.install_dvr_process_ipv6(
+ vlan_tag=lvm.vlan, gateway_mac=subnet_info['gateway_mac'])
+ br.install_dvr_process(
+ vlan_tag=lvm.vlan, vif_mac=port.vif_mac,
+ dvr_mac_address=self.dvr_mac_address)
+
# the dvr router interface is itself a port, so capture it
# queue this subnet to that port. A subnet appears only once as
# a router interface on any given router
port.vif_mac, device_owner)
ovsport.add_subnet(subnet_uuid)
self.local_ports[port.vif_id] = ovsport
- table_id = constants.DVR_TO_SRC_MAC
vlan_to_use = lvm.vlan
if lvm.network_type == p_const.TYPE_VLAN:
- table_id = constants.DVR_TO_SRC_MAC_VLAN
vlan_to_use = lvm.segmentation_id
# create a rule for this vm port
- self.int_br.add_flow(table=table_id,
- priority=4,
- dl_vlan=vlan_to_use,
- dl_dst=ovsport.get_mac(),
- actions="strip_vlan,mod_dl_src:%s,"
- "output:%s" %
- (subnet_info['gateway_mac'],
- ovsport.get_ofport()))
+ self.int_br.install_dvr_to_src_mac(
+ network_type=lvm.network_type,
+ vlan_tag=vlan_to_use,
+ gateway_mac=subnet_info['gateway_mac'],
+ dst_mac=ovsport.get_mac(),
+ dst_port=ovsport.get_ofport())
def _bind_centralized_snat_port_on_dvr_subnet(self, port, lvm,
fixed_ips, device_owner):
port.vif_mac, device_owner)
ovsport.add_subnet(subnet_uuid)
self.local_ports[port.vif_id] = ovsport
- table_id = constants.DVR_TO_SRC_MAC
vlan_to_use = lvm.vlan
if lvm.network_type == p_const.TYPE_VLAN:
- table_id = constants.DVR_TO_SRC_MAC_VLAN
vlan_to_use = lvm.segmentation_id
- self.int_br.add_flow(table=table_id,
- priority=4,
- dl_vlan=vlan_to_use,
- dl_dst=ovsport.get_mac(),
- actions="strip_vlan,mod_dl_src:%s,"
- " output:%s" %
- (subnet_info['gateway_mac'],
- ovsport.get_ofport()))
+ self.int_br.install_dvr_to_src_mac(
+ network_type=lvm.network_type,
+ vlan_tag=vlan_to_use,
+ gateway_mac=subnet_info['gateway_mac'],
+ dst_mac=ovsport.get_mac(),
+ dst_port=ovsport.get_ofport())
def bind_port_to_dvr(self, port, local_vlan_map,
fixed_ips, device_owner):
subnet_set = set(subnet_ids)
network_type = lvm.network_type
physical_network = lvm.physical_network
- table_id = constants.DVR_TO_SRC_MAC
vlan_to_use = lvm.vlan
if network_type == p_const.TYPE_VLAN:
- table_id = constants.DVR_TO_SRC_MAC_VLAN
vlan_to_use = lvm.segmentation_id
# ensure we process for all the subnets laid on this removed port
for sub_uuid in subnet_set:
compute_ports = ldm.get_compute_ofports()
for vif_id in compute_ports:
comp_port = self.local_ports[vif_id]
- self.int_br.delete_flows(table=table_id,
- dl_vlan=vlan_to_use,
- dl_dst=comp_port.get_mac())
+ self.int_br.delete_dvr_to_src_mac(
+ network_type=network_type,
+ vlan_tag=vlan_to_use, dst_mac=comp_port.get_mac())
ldm.remove_all_compute_ofports()
if ldm.get_csnat_ofport() == constants.OFPORT_INVALID:
# ports available on this agent anymore
self.local_dvr_map.pop(sub_uuid, None)
if network_type == p_const.TYPE_VLAN:
- args = {'table': constants.DVR_PROCESS_VLAN,
- 'dl_vlan': lvm.vlan}
- if ip_version == 4:
- args['proto'] = 'arp'
- args['nw_dst'] = subnet_info['gateway_ip']
- else:
- args['proto'] = 'icmp6'
- args['icmp_type'] = n_const.ICMPV6_TYPE_RA
- args['dl_src'] = subnet_info['gateway_mac']
- self.phys_br[physical_network].delete_flows(**args)
-
+ br = self.phys_br[physical_network]
if network_type in constants.TUNNEL_NETWORK_TYPES:
- args = {'table': constants.DVR_PROCESS,
- 'dl_vlan': lvm.vlan}
- if ip_version == 4:
- args['proto'] = 'arp'
- args['nw_dst'] = subnet_info['gateway_ip']
- else:
- args['proto'] = 'icmp6'
- args['icmp_type'] = n_const.ICMPV6_TYPE_RA
- args['dl_src'] = subnet_info['gateway_mac']
- self.tun_br.delete_flows(**args)
+ br = self.tun_br
+ if ip_version == 4:
+ br.delete_dvr_process_ipv4(
+ vlan_tag=lvm.vlan, gateway_ip=subnet_info['gateway_ip'])
+ else:
+ br.delete_dvr_process_ipv6(
+ vlan_tag=lvm.vlan, gateway_mac=subnet_info['gateway_mac'])
ovsport.remove_subnet(sub_uuid)
if lvm.network_type == p_const.TYPE_VLAN:
- self.phys_br[physical_network].delete_flows(
- table=constants.DVR_PROCESS_VLAN,
- dl_vlan=lvm.vlan,
- dl_dst=port.vif_mac)
- self.phys_br[physical_network].delete_flows(
- table=constants.DVR_PROCESS_VLAN,
- dl_vlan=lvm.vlan,
- dl_src=port.vif_mac)
-
+ br = self.phys_br[physical_network]
if lvm.network_type in constants.TUNNEL_NETWORK_TYPES:
- self.tun_br.delete_flows(table=constants.DVR_PROCESS,
- dl_vlan=lvm.vlan,
- dl_dst=port.vif_mac)
- self.tun_br.delete_flows(table=constants.DVR_PROCESS,
- dl_vlan=lvm.vlan,
- dl_src=port.vif_mac)
+ br = self.tun_br
+ br.delete_dvr_process(vlan_tag=lvm.vlan, vif_mac=port.vif_mac)
+
# release port state
self.local_ports.pop(port.vif_id, None)
continue
ldm = self.local_dvr_map[sub_uuid]
ldm.remove_compute_ofport(port.vif_id)
- table_id = constants.DVR_TO_SRC_MAC
vlan_to_use = lvm.vlan
if lvm.network_type == p_const.TYPE_VLAN:
- table_id = constants.DVR_TO_SRC_MAC_VLAN
vlan_to_use = lvm.segmentation_id
# first remove this vm port rule
- self.int_br.delete_flows(table=table_id,
- dl_vlan=vlan_to_use,
- dl_dst=ovsport.get_mac())
+ self.int_br.delete_dvr_to_src_mac(
+ network_type=lvm.network_type,
+ vlan_tag=vlan_to_use, dst_mac=ovsport.get_mac())
# release port state
self.local_ports.pop(port.vif_id, None)
return
ldm = self.local_dvr_map[sub_uuid]
ldm.set_csnat_ofport(constants.OFPORT_INVALID)
- table_id = constants.DVR_TO_SRC_MAC
vlan_to_use = lvm.vlan
if lvm.network_type == p_const.TYPE_VLAN:
- table_id = constants.DVR_TO_SRC_MAC_VLAN
vlan_to_use = lvm.segmentation_id
# then remove csnat port rule
- self.int_br.delete_flows(table=table_id,
- dl_vlan=vlan_to_use,
- dl_dst=ovsport.get_mac())
+ self.int_br.delete_dvr_to_src_mac(
+ network_type=lvm.network_type,
+ vlan_tag=vlan_to_use, dst_mac=ovsport.get_mac())
if not ldm.is_dvr_owned():
# if not owned by DVR (only used for csnat), remove this
# subnet state altogether
-#!/usr/bin/env python
# Copyright 2011 VMware, Inc.
# All Rights Reserved.
#
import oslo_messaging
from six import moves
-from neutron.agent.common import config
from neutron.agent.common import ovs_lib
from neutron.agent.common import polling
from neutron.agent.common import utils
from neutron.agent import rpc as agent_rpc
from neutron.agent import securitygroups_rpc as sg_rpc
from neutron.api.rpc.handlers import dvr_rpc
-from neutron.common import config as common_config
from neutron.common import constants as q_const
from neutron.common import exceptions
from neutron.common import topics
LOG = logging.getLogger(__name__)
cfg.CONF.import_group('AGENT', 'neutron.plugins.openvswitch.common.config')
+cfg.CONF.import_group('OVS', 'neutron.plugins.openvswitch.common.config')
# A placeholder for dead vlans.
DEAD_VLAN_TAG = p_const.MAX_VLAN_TAG + 1
+class _mac_mydialect(netaddr.mac_unix):
+ word_fmt = '%.2x'
+
+
class DeviceListRetrievalError(exceptions.NeutronException):
message = _("Unable to retrieve port details for devices: %(devices)s "
"because of error: %(error)s")
# 1.2 Support DVR (Distributed Virtual Router) RPC
target = oslo_messaging.Target(version='1.2')
- def __init__(self, integ_br, tun_br, local_ip,
+ def __init__(self, bridge_classes, integ_br, tun_br, local_ip,
bridge_mappings, polling_interval, tunnel_types=None,
veth_mtu=None, l2_population=False,
enable_distributed_routing=False,
quitting_rpc_timeout=None):
'''Constructor.
+ :param bridge_classes: a dict for bridge classes.
:param integ_br: name of the integration bridge.
:param tun_br: name of the tunnel bridge.
:param local_ip: local IP address of this hypervisor.
SIGTERM is received
'''
super(OVSNeutronAgent, self).__init__()
+ 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.use_veth_interconnection = use_veth_interconnection
self.veth_mtu = veth_mtu
self.available_local_vlans = set(moves.range(p_const.MIN_VLAN_TAG,
# Keep track of int_br's device count for use by _report_state()
self.int_br_device_count = 0
- self.int_br = ovs_lib.OVSBridge(integ_br)
+ self.int_br = self.br_int_cls(integ_br)
self.setup_integration_br()
# Stores port update notifications for processing in main rpc loop
self.updated_ports = set()
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 = _ofport_set_to_str(lvm.tun_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))
+ br.install_flood_to_tun(lvm.vlan, lvm.segmentation_id,
+ lvm.tun_ofports)
else:
self.setup_entry_for_arp_reply(br, 'add', lvm.vlan,
port_info.mac_address,
port_info.ip_address)
- br.add_flow(table=constants.UCAST_TO_TUN,
- priority=2,
- dl_vlan=lvm.vlan,
- dl_dst=port_info.mac_address,
- actions="strip_vlan,set_tunnel:%s,output:%s" %
- (lvm.segmentation_id, ofport))
+ br.install_unicast_to_tun(lvm.vlan,
+ lvm.segmentation_id,
+ ofport,
+ port_info.mac_address)
def del_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
if port_info == q_const.FLOODING_ENTRY:
return
lvm.tun_ofports.remove(ofport)
if len(lvm.tun_ofports) > 0:
- ofports = _ofport_set_to_str(lvm.tun_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))
+ br.install_flood_to_tun(lvm.vlan, lvm.segmentation_id,
+ lvm.tun_ofports)
else:
# This local vlan doesn't require any more tunnelling
- br.delete_flows(table=constants.FLOOD_TO_TUN, dl_vlan=lvm.vlan)
+ br.delete_flood_to_tun(lvm.vlan)
else:
self.setup_entry_for_arp_reply(br, 'remove', lvm.vlan,
port_info.mac_address,
port_info.ip_address)
- br.delete_flows(table=constants.UCAST_TO_TUN,
- dl_vlan=lvm.vlan,
- dl_dst=port_info.mac_address)
+ br.delete_unicast_to_tun(lvm.vlan, port_info.mac_address)
def _fdb_chg_ip(self, context, fdb_entries):
LOG.debug("update chg_ip received")
if not self.arp_responder_enabled:
return
- mac = netaddr.EUI(mac_address, dialect=netaddr.mac_unix)
- ip = netaddr.IPAddress(ip_address)
+ mac = str(netaddr.EUI(mac_address, dialect=_mac_mydialect))
+ ip = str(netaddr.IPAddress(ip_address))
if action == 'add':
- actions = constants.ARP_RESPONDER_ACTIONS % {'mac': mac, 'ip': ip}
- br.add_flow(table=constants.ARP_RESPONDER,
- priority=1,
- proto='arp',
- dl_vlan=local_vid,
- nw_dst='%s' % ip,
- actions=actions)
+ br.install_arp_responder(local_vid, ip, mac)
elif action == 'remove':
- br.delete_flows(table=constants.ARP_RESPONDER,
- proto='arp',
- dl_vlan=local_vid,
- nw_dst='%s' % ip)
+ br.delete_arp_responder(local_vid, ip)
else:
LOG.warning(_LW('Action %s not supported'), action)
+ def _local_vlan_for_flat(self, lvid, physical_network):
+ phys_br = self.phys_brs[physical_network]
+ phys_port = self.phys_ofports[physical_network]
+ int_br = self.int_br
+ int_port = self.int_ofports[physical_network]
+ phys_br.provision_local_vlan(port=phys_port, lvid=lvid,
+ segmentation_id=None,
+ distributed=False)
+ int_br.provision_local_vlan(port=int_port, lvid=lvid,
+ segmentation_id=None)
+
+ def _local_vlan_for_vlan(self, lvid, physical_network, segmentation_id):
+ distributed = self.enable_distributed_routing
+ phys_br = self.phys_brs[physical_network]
+ phys_port = self.phys_ofports[physical_network]
+ int_br = self.int_br
+ int_port = self.int_ofports[physical_network]
+ phys_br.provision_local_vlan(port=phys_port, lvid=lvid,
+ segmentation_id=segmentation_id,
+ distributed=distributed)
+ int_br.provision_local_vlan(port=int_port, lvid=lvid,
+ segmentation_id=segmentation_id)
+
def provision_local_vlan(self, net_uuid, network_type, physical_network,
segmentation_id, local_vlan=None):
'''Provisions a local VLAN.
if network_type in constants.TUNNEL_NETWORK_TYPES:
if self.enable_tunneling:
# outbound broadcast/multicast
- ofports = _ofport_set_to_str(
- self.tun_br_ofports[network_type].values())
+ ofports = self.tun_br_ofports[network_type].values()
if ofports:
- self.tun_br.mod_flow(table=constants.FLOOD_TO_TUN,
- dl_vlan=lvid,
- actions="strip_vlan,"
- "set_tunnel:%s,output:%s" %
- (segmentation_id, ofports))
+ self.tun_br.install_flood_to_tun(lvid,
+ segmentation_id,
+ ofports)
# inbound from tunnels: set lvid in the right table
# and resubmit to Table LEARN_FROM_TUN for mac learning
if self.enable_distributed_routing:
self.dvr_agent.process_tunneled_network(
network_type, lvid, segmentation_id)
else:
- self.tun_br.add_flow(
- table=constants.TUN_TABLE[network_type],
- priority=1,
- tun_id=segmentation_id,
- actions="mod_vlan_vid:%s,"
- "resubmit(,%s)" %
- (lvid, constants.LEARN_FROM_TUN))
-
+ self.tun_br.provision_local_vlan(
+ network_type=network_type, lvid=lvid,
+ segmentation_id=segmentation_id)
else:
LOG.error(_LE("Cannot provision %(network_type)s network for "
"net-id=%(net_uuid)s - tunneling disabled"),
'net_uuid': net_uuid})
elif network_type == p_const.TYPE_FLAT:
if physical_network in self.phys_brs:
- # outbound
- br = self.phys_brs[physical_network]
- br.add_flow(priority=4,
- in_port=self.phys_ofports[physical_network],
- dl_vlan=lvid,
- actions="strip_vlan,normal")
- # inbound
- self.int_br.add_flow(
- priority=3,
- in_port=self.int_ofports[physical_network],
- dl_vlan=0xffff,
- actions="mod_vlan_vid:%s,normal" % lvid)
+ self._local_vlan_for_flat(lvid, physical_network)
else:
LOG.error(_LE("Cannot provision flat network for "
"net-id=%(net_uuid)s - no bridge for "
'physical_network': physical_network})
elif network_type == p_const.TYPE_VLAN:
if physical_network in self.phys_brs:
- # outbound
- br = self.phys_brs[physical_network]
- if self.enable_distributed_routing:
- br.add_flow(table=constants.LOCAL_VLAN_TRANSLATION,
- priority=4,
- in_port=self.phys_ofports[physical_network],
- dl_vlan=lvid,
- actions="mod_vlan_vid:%s,normal" % segmentation_id)
- else:
- br.add_flow(priority=4,
- in_port=self.phys_ofports[physical_network],
- dl_vlan=lvid,
- actions="mod_vlan_vid:%s,normal" % segmentation_id)
-
- # inbound
- self.int_br.add_flow(priority=3,
- in_port=self.
- int_ofports[physical_network],
- dl_vlan=segmentation_id,
- actions="mod_vlan_vid:%s,normal" % lvid)
+ self._local_vlan_for_vlan(lvid, physical_network,
+ segmentation_id)
else:
LOG.error(_LE("Cannot provision VLAN network for "
"net-id=%(net_uuid)s - no bridge for "
if lvm.network_type in constants.TUNNEL_NETWORK_TYPES:
if self.enable_tunneling:
- self.tun_br.delete_flows(
- table=constants.TUN_TABLE[lvm.network_type],
- tun_id=lvm.segmentation_id)
- self.tun_br.delete_flows(dl_vlan=lvm.vlan)
+ self.tun_br.reclaim_local_vlan(
+ network_type=lvm.network_type,
+ segmentation_id=lvm.segmentation_id)
+ self.tun_br.delete_flood_to_tun(lvm.vlan)
+ self.tun_br.delete_unicast_to_tun(lvm.vlan, None)
+ self.tun_br.delete_arp_responder(lvm.vlan, None)
if self.l2_pop:
# Try to remove tunnel ports if not used by other networks
for ofport in lvm.tun_ofports:
if lvm.physical_network in self.phys_brs:
# outbound
br = self.phys_brs[lvm.physical_network]
- br.delete_flows(in_port=self.phys_ofports[lvm.
- physical_network],
- dl_vlan=lvm.vlan)
+ br.reclaim_local_vlan(
+ port=self.phys_ofports[lvm.physical_network],
+ lvid=lvm.vlan)
# inbound
br = self.int_br
- br.delete_flows(in_port=self.int_ofports[lvm.physical_network],
- dl_vlan=0xffff)
+ br.reclaim_local_vlan(
+ port=self.int_ofports[lvm.physical_network],
+ segmentation_id=None)
elif lvm.network_type == p_const.TYPE_VLAN:
if lvm.physical_network in self.phys_brs:
# outbound
br = self.phys_brs[lvm.physical_network]
- br.delete_flows(in_port=self.phys_ofports[lvm.
- physical_network],
- dl_vlan=lvm.vlan)
+ br.reclaim_local_vlan(
+ port=self.phys_ofports[lvm.physical_network],
+ lvid=lvm.vlan)
# inbound
br = self.int_br
- br.delete_flows(in_port=self.int_ofports[lvm.physical_network],
- dl_vlan=lvm.segmentation_id)
+ br.reclaim_local_vlan(
+ port=self.int_ofports[lvm.physical_network],
+ segmentation_id=lvm.segmentation_id)
elif lvm.network_type == p_const.TYPE_LOCAL:
# no flows needed for local networks
pass
self.int_br.set_db_attribute(
"Port", port.port_name, "tag", lvm.vlan)
if port.ofport != -1:
+ # NOTE(yamamoto): Remove possible drop_port flow
+ # installed by port_dead.
self.int_br.delete_flows(in_port=port.ofport)
# update plugin about port status
@staticmethod
def setup_arp_spoofing_protection(bridge, vif, port_details):
# clear any previous flows related to this port in our ARP table
- bridge.delete_flows(table=constants.LOCAL_SWITCHING,
- in_port=vif.ofport, proto='arp')
- bridge.delete_flows(table=constants.ARP_SPOOF_TABLE,
- in_port=vif.ofport)
+ bridge.delete_arp_spoofing_protection(port=vif.ofport)
if not port_details.get('port_security_enabled', True):
LOG.info(_LI("Skipping ARP spoofing rules for port '%s' because "
"it has port security disabled"), vif.port_name)
return
- # all of the rules here are based on 'in_port' match criteria
- # so their cleanup will be handled by 'update_stale_ofport_rules'
-
# collect all of the addresses and cidrs that belong to the port
- addresses = [f['ip_address'] for f in port_details['fixed_ips']]
+ addresses = {f['ip_address'] for f in port_details['fixed_ips']}
if port_details.get('allowed_address_pairs'):
- addresses += [p['ip_address']
- for p in port_details['allowed_address_pairs']]
+ addresses |= {p['ip_address']
+ for p in port_details['allowed_address_pairs']}
- # allow ARPs as long as they match addresses that actually
- # belong to the port.
- for ip in addresses:
- if netaddr.IPNetwork(ip).version != 4:
- continue
- bridge.add_flow(table=constants.ARP_SPOOF_TABLE, priority=2,
- proto='arp', arp_spa=ip, in_port=vif.ofport,
- actions="NORMAL")
-
- # drop any ARPs in this table that aren't explicitly allowed
- bridge.add_flow(table=constants.ARP_SPOOF_TABLE, priority=1,
- proto='arp', actions="DROP")
-
- # 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.
- bridge.add_flow(table=constants.LOCAL_SWITCHING,
- priority=10, proto='arp', in_port=vif.ofport,
- actions=("resubmit(,%s)" % constants.ARP_SPOOF_TABLE))
+ addresses = {ip for ip in addresses
+ if netaddr.IPNetwork(ip).version == 4}
+
+ bridge.install_arp_spoofing_protection(port=vif.ofport,
+ ip_addresses=addresses)
def port_unbound(self, vif_id, net_uuid=None):
'''Unbind port.
if cur_tag != DEAD_VLAN_TAG:
self.int_br.set_db_attribute("Port", port.port_name, "tag",
DEAD_VLAN_TAG)
- self.int_br.add_flow(priority=2, in_port=port.ofport,
- actions="drop")
+ self.int_br.drop_port(in_port=port.ofport)
def setup_integration_br(self):
'''Setup the integration bridge.
# which does nothing if bridge already exists.
self.int_br.create()
self.int_br.set_secure_mode()
+ self.int_br.setup_controllers(cfg.CONF)
self.int_br.delete_port(cfg.CONF.OVS.int_peer_patch_port)
- self.int_br.remove_all_flows()
- # switch all traffic using L2 learning
- self.int_br.add_flow(priority=1, actions="normal")
- # Add a canary flow to int_br to track OVS restarts
- self.int_br.add_flow(table=constants.CANARY_TABLE, priority=0,
- actions="drop")
+
+ self.int_br.setup_default_table()
def setup_ancillary_bridges(self, integ_br, tun_br):
'''Setup ancillary bridges - for example br-ex.'''
:param tun_br_name: the name of the tunnel bridge.
'''
if not self.tun_br:
- self.tun_br = ovs_lib.OVSBridge(tun_br_name)
+ self.tun_br = self.br_tun_cls(tun_br_name)
self.tun_br.reset_bridge(secure_mode=True)
+ self.tun_br.setup_controllers(cfg.CONF)
self.patch_tun_ofport = self.int_br.add_patch_port(
cfg.CONF.OVS.int_peer_patch_port, cfg.CONF.OVS.tun_peer_patch_port)
self.patch_int_ofport = self.tun_br.add_patch_port(
"version of OVS does not support tunnels or patch "
"ports. Agent terminated!"))
exit(1)
- self.tun_br.remove_all_flows()
+ self.tun_br.delete_flows()
def setup_tunnel_br(self):
'''Setup the tunnel bridge.
Add all flows to the tunnel bridge.
'''
- # Table 0 (default) will sort incoming traffic depending on in_port
- self.tun_br.add_flow(priority=1,
- in_port=self.patch_int_ofport,
- actions="resubmit(,%s)" %
- constants.PATCH_LV_TO_TUN)
- self.tun_br.add_flow(priority=0, actions="drop")
- if self.arp_responder_enabled:
- # ARP broadcast-ed request go to the local ARP_RESPONDER table to
- # be locally resolved
- self.tun_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
- self.tun_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
- self.tun_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:
- self.tun_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 = ("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[]" %
- constants.UCAST_TO_TUN)
- # Once remote mac addresses are learnt, output packet to patch_int
- self.tun_br.add_flow(table=constants.LEARN_FROM_TUN,
- priority=1,
- actions="learn(%s),output:%s" %
- (learned_flow, self.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
- self.tun_br.add_flow(table=constants.UCAST_TO_TUN,
- priority=0,
- actions="resubmit(,%s)" %
- constants.FLOOD_TO_TUN)
- if self.arp_responder_enabled:
- # If none of the ARP entries correspond to the requested IP, the
- # broadcast-ed packet is resubmitted to the flooding table
- self.tun_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.tun_br.add_flow(table=constants.FLOOD_TO_TUN,
- priority=0,
- actions="drop")
+ self.tun_br.setup_default_table(self.patch_int_ofport,
+ self.arp_responder_enabled)
def get_peer_name(self, prefix, name):
"""Construct a peer name based on the prefix and name.
{'physical_network': physical_network,
'bridge': bridge})
sys.exit(1)
- br = ovs_lib.OVSBridge(bridge)
- br.remove_all_flows()
- br.add_flow(priority=1, actions="normal")
+ br = self.br_phys_cls(bridge)
+ br.setup_controllers(cfg.CONF)
+ br.setup_default_table()
self.phys_brs[physical_network] = br
# interconnect physical and integration bridges using veth/patchs
self.phys_ofports[physical_network] = phys_ofport
# block all untranslated traffic between bridges
- self.int_br.add_flow(priority=2, in_port=int_ofport,
- actions="drop")
- br.add_flow(priority=2, in_port=phys_ofport, actions="drop")
+ self.int_br.drop_port(in_port=int_ofport)
+ br.drop_port(in_port=phys_ofport)
if self.use_veth_interconnection:
# enable veth to pass traffic
# delete any stale rules based on removed ofports
ofports_deleted = set(previous.values()) - set(current.values())
for ofport in ofports_deleted:
- self.int_br.delete_flows(in_port=ofport)
+ self.int_br.delete_arp_spoofing_protection(port=ofport)
# store map for next iteration
self.vifname_to_ofport_map = current
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)
- br.add_flow(priority=1,
- in_port=ofport,
- actions="resubmit(,%s)" %
- constants.TUN_TABLE[tunnel_type])
+ br.setup_tunnel_port(tunnel_type, ofport)
- ofports = _ofport_set_to_str(self.tun_br_ofports[tunnel_type].values())
+ ofports = self.tun_br_ofports[tunnel_type].values()
if ofports and not self.l2_pop:
# Update flooding flows to include the new tunnel
for vlan_mapping in list(self.local_vlan_map.values()):
if vlan_mapping.network_type == tunnel_type:
- 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.install_flood_to_tun(vlan_mapping.vlan,
+ vlan_mapping.segmentation_id,
+ ofports)
return ofport
def setup_tunnel_port(self, br, remote_ip, network_type):
port_name = '%s-%s' % (tunnel_type,
self.get_ip_in_hex(remote_ip))
br.delete_port(port_name)
- br.delete_flows(in_port=ofport)
+ br.cleanup_tunnel_port(ofport)
self.tun_br_ofports[tunnel_type].pop(remote_ip, None)
def treat_devices_added_or_updated(self, devices, ovs_restarted):
def check_ovs_status(self):
# Check for the canary flow
- canary_flow = self.int_br.dump_flows_for_table(constants.CANARY_TABLE)
- if canary_flow == '':
+ status = self.int_br.check_canary_table()
+ if status == constants.OVS_RESTARTED:
LOG.warn(_LW("OVS is restarted. OVSNeutronAgent will reset "
"bridges and recover ports."))
- return constants.OVS_RESTARTED
- elif canary_flow is None:
+ elif status == constants.OVS_DEAD:
LOG.warn(_LW("OVS is dead. OVSNeutronAgent will keep running "
"and checking OVS status periodically."))
- return constants.OVS_DEAD
- else:
- # OVS is in normal status
- return constants.OVS_NORMAL
+ return status
def loop_count_and_wait(self, start_time, port_stats):
# sleep till end of polling interval
self.loop_count_and_wait(start, port_stats)
def daemon_loop(self):
+ # Start everything.
+ LOG.info(_LI("Agent initialized successfully, now running... "))
+ signal.signal(signal.SIGTERM, self._handle_sigterm)
with polling.get_polling_manager(
self.minimize_polling,
self.ovsdb_monitor_respawn_interval) as pm:
"Agent and Server side."))
-def _ofport_set_to_str(ofport_set):
- return ",".join(map(str, ofport_set))
-
-
def create_agent_config_map(config):
"""Create a map of agent config parameters.
return kwargs
-def main():
- cfg.CONF.register_opts(ip_lib.OPTS)
- config.register_root_helper(cfg.CONF)
- common_config.init(sys.argv[1:])
- common_config.setup_logging()
- q_utils.log_opt_values(LOG)
-
- try:
- agent_config = create_agent_config_map(cfg.CONF)
- except ValueError as e:
- LOG.error(_LE('%s Agent terminated!'), e)
- sys.exit(1)
-
+def prepare_xen_compute():
is_xen_compute_host = 'rootwrap-xen-dom0' in cfg.CONF.AGENT.root_helper
if is_xen_compute_host:
# Force ip_lib to always use the root helper to ensure that ip
# commands target xen dom0 rather than domU.
+ cfg.CONF.register_opts(ip_lib.OPTS)
cfg.CONF.set_default('ip_lib_force_root', True)
+
+def main(bridge_classes):
+ try:
+ agent_config = create_agent_config_map(cfg.CONF)
+ except ValueError:
+ LOG.exception(_LE("Agent failed to create agent config map"))
+ raise SystemExit(1)
+ prepare_xen_compute()
try:
- agent = OVSNeutronAgent(**agent_config)
+ agent = OVSNeutronAgent(bridge_classes, **agent_config)
except RuntimeError as e:
LOG.error(_LE("%s Agent terminated!"), e)
sys.exit(1)
- signal.signal(signal.SIGTERM, agent._handle_sigterm)
-
- # Start everything.
- LOG.info(_LI("Agent initialized successfully, now running... "))
agent.daemon_loop()
-
-
-if __name__ == "__main__":
- main()
cfg.BoolOpt('use_veth_interconnection', default=False,
help=_("Use veths instead of patch ports to interconnect the "
"integration bridge to physical bridges.")),
+ cfg.StrOpt('of_interface', default='ovs-ofctl', choices=['ovs-ofctl'],
+ help=_("OpenFlow interface to use.")),
]
agent_opts = [
# License for the specific language governing permissions and limitations
# under the License.
+import eventlet
+import mock
+
+from oslo_config import cfg
+from oslo_utils import importutils
+
from neutron.agent.linux import ip_lib
from neutron.cmd.sanity import checks
from neutron.plugins.openvswitch.agent import ovs_neutron_agent as ovsagt
+from neutron.plugins.openvswitch.common import constants
from neutron.tests.common import machine_fixtures
from neutron.tests.common import net_helpers
from neutron.tests.functional.agent import test_ovs_lib
from neutron.tests import tools
-class ARPSpoofTestCase(test_ovs_lib.OVSBridgeTestBase,
- base.BaseSudoTestCase):
+cfg.CONF.import_group('OVS', 'neutron.plugins.openvswitch.common.config')
+
+class _OVSAgentTestBase(test_ovs_lib.OVSBridgeTestBase,
+ base.BaseSudoTestCase):
+ 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_thread = eventlet.spawn(self._kick_main)
+ self.addCleanup(self._kill_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.
+ while not self.init_done:
+ self.init_done_ev.wait()
+
+ def _kick_main(self):
+ with mock.patch.object(ovsagt, 'main', self._agent_main):
+ self.of_interface_mod.main()
+
+ def _kill_main(self):
+ self._main_thread.kill()
+ 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()
+
+
+class _OVSAgentOFCtlTestBase(_OVSAgentTestBase):
+ _MAIN_MODULE = 'neutron.plugins.openvswitch.agent.openflow.ovs_ofctl.main'
+
+
+class _ARPSpoofTestCase(object):
def setUp(self):
if not checks.arp_header_match_supported():
self.skipTest("ARP header matching not supported")
# NOTE(kevinbenton): it would be way cooler to use scapy for
# these but scapy requires the python process to be running as
# root to bind to the ports.
- super(ARPSpoofTestCase, self).setUp()
+ super(_ARPSpoofTestCase, self).setUp()
self.src_addr = '192.168.0.1'
self.dst_addr = '192.168.0.2'
self.src_namespace = self.useFixture(
'allowed_address_pairs': [
dict(ip_address=ip) for ip in addrs]}
ovsagt.OVSNeutronAgent.setup_arp_spoofing_protection(
- self.br, VifPort(), details)
+ self.br_int, VifPort(), details)
+
+
+class ARPSpoofOFCtlTestCase(_ARPSpoofTestCase, _OVSAgentOFCtlTestBase):
+ pass
+
+
+class _CanaryTableTestCase(object):
+ def test_canary_table(self):
+ self.br_int.delete_flows()
+ self.assertEqual(constants.OVS_RESTARTED,
+ self.br_int.check_canary_table())
+ self.br_int.setup_canary_table()
+ self.assertEqual(constants.OVS_NORMAL,
+ self.br_int.check_canary_table())
+
+
+class CanaryTableOFCtlTestCase(_CanaryTableTestCase, _OVSAgentOFCtlTestBase):
+ pass
--- /dev/null
+# 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.tests.unit.plugins.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)
+
+
+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),
+ ]
+ 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'),
+ ]
+ 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)
--- /dev/null
+# 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.tests.unit.plugins.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.delete_flows(),
+ call.add_flow(priority=0, table=0, actions='normal'),
+ call.add_flow(priority=0, table=23, actions='drop'),
+ call.add_flow(priority=0, table=24, actions='drop'),
+ ]
+ 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,normal' % 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,normal' % 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='strip_vlan,mod_dl_src:%(mac)s,'
+ 'output:%(port)s' % {
+ 'mac': gateway_mac,
+ '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(table=1, 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='strip_vlan,mod_dl_src:%(mac)s,'
+ 'output:%(port)s' % {
+ 'mac': gateway_mac,
+ '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(table=2, 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(eth_src=mac, table_id=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(eth_src=mac, table_id=0, in_port=port),
+ ]
+ 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='normal',
+ arp_spa='192.0.2.1',
+ priority=2, table=24, in_port=8888),
+ call.add_flow(proto='arp', actions='normal',
+ 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_id=0, in_port=8888, proto='arp'),
+ call.delete_flows(table_id=24, in_port=8888),
+ ]
+ self.assertEqual(expected, self.mock.mock_calls)
--- /dev/null
+# 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.openvswitch.common.constants as ovs_const
+from neutron.tests.unit.plugins.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.delete_flows(),
+ 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(eth_src=mac, table_id=3),
+ ]
+ self.assertEqual(expected, self.mock.mock_calls)
--- /dev/null
+# 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.openvswitch.common.constants as ovs_const
+from neutron.tests.unit.plugins.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)
+
+ def test_setup_default_table(self):
+ patch_int_ofport = 5555
+ arp_responder_enabled = False
+ self.br.setup_default_table(patch_int_ofport=patch_int_ofport,
+ arp_responder_enabled=arp_responder_enabled)
+ expected = [
+ call.add_flow(priority=1, in_port=patch_int_ofport,
+ actions='resubmit(,2)'),
+ call.add_flow(priority=0, actions='drop'),
+ call.add_flow(priority=0, table=2,
+ dl_dst='00:00:00:00:00:00/01:00:00:00:00:00',
+ actions='resubmit(,20)'),
+ call.add_flow(priority=0, table=2,
+ dl_dst='01:00:00:00:00:00/01:00:00:00:00:00',
+ actions='resubmit(,22)'),
+ call.add_flow(priority=0, table=3, actions='drop'),
+ call.add_flow(priority=0, table=4, actions='drop'),
+ call.add_flow(priority=1, table=10,
+ actions='learn(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),
+ call.add_flow(priority=0, table=20, actions='resubmit(,22)'),
+ 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
+ arp_responder_enabled = True
+ self.br.setup_default_table(patch_int_ofport=patch_int_ofport,
+ arp_responder_enabled=arp_responder_enabled)
+ expected = [
+ call.add_flow(priority=1, in_port=patch_int_ofport,
+ actions='resubmit(,2)'),
+ call.add_flow(priority=0, actions='drop'),
+ call.add_flow(priority=1, table=2, dl_dst='ff:ff:ff:ff:ff:ff',
+ actions='resubmit(,21)', proto='arp'),
+ call.add_flow(priority=0, table=2,
+ dl_dst='00:00:00:00:00:00/01:00:00:00:00:00',
+ actions='resubmit(,20)'),
+ call.add_flow(priority=0, table=2,
+ dl_dst='01:00:00:00:00:00/01:00:00:00:00:00',
+ actions='resubmit(,22)'),
+ call.add_flow(priority=0, table=3, actions='drop'),
+ call.add_flow(priority=0, table=4, actions='drop'),
+ call.add_flow(priority=1, table=10,
+ actions='learn(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),
+ call.add_flow(priority=0, table=20, actions='resubmit(,22)'),
+ call.add_flow(priority=0, table=21, actions='resubmit(,22)'),
+ 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(eth_src=mac, table_id=9),
+ ]
+ self.assertEqual(expected, self.mock.mock_calls)
--- /dev/null
+# Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
+# Copyright (C) 2014 Fumihiko Kakuma <kakuma at valinux co jp>
+# 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 oslo_utils import importutils
+
+from neutron.tests import base
+
+
+_AGENT_PACKAGE = 'neutron.plugins.openvswitch.agent'
+_AGENT_NAME = _AGENT_PACKAGE + '.ovs_neutron_agent'
+_DVR_AGENT_NAME = 'neutron.plugins.openvswitch.agent.ovs_dvr_neutron_agent'
+
+
+class OVSAgentConfigTestBase(base.BaseTestCase):
+ def setUp(self):
+ super(OVSAgentConfigTestBase, self).setUp()
+ self.mod_agent = importutils.import_module(_AGENT_NAME)
+ self.mod_dvr_agent = importutils.import_module(_DVR_AGENT_NAME)
+
+
+class OVSAgentTestBase(OVSAgentConfigTestBase):
+ def setUp(self):
+ super(OVSAgentTestBase, self).setUp()
+ 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)
+
+ 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'
import time
import mock
-import netaddr
from oslo_config import cfg
from oslo_log import log
import oslo_messaging
from neutron.common import constants as n_const
from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2.drivers.l2pop import rpc as l2pop_rpc
-from neutron.plugins.openvswitch.agent import ovs_neutron_agent
from neutron.plugins.openvswitch.common import constants
-from neutron.tests import base
+from neutron.tests.unit.plugins.openvswitch.agent import ovs_test_base
NOTIFIER = 'neutron.plugins.ml2.rpc.AgentNotifierApi'
port_name = 'name'
-class CreateAgentConfigMap(base.BaseTestCase):
+class CreateAgentConfigMap(ovs_test_base.OVSAgentConfigTestBase):
def test_create_agent_config_map_succeeds(self):
- self.assertTrue(ovs_neutron_agent.create_agent_config_map(cfg.CONF))
+ self.assertTrue(self.mod_agent.create_agent_config_map(cfg.CONF))
def test_create_agent_config_map_fails_for_invalid_tunnel_config(self):
# An ip address is required for tunneling but there is no default,
cfg.CONF.set_override('tunnel_types', [p_const.TYPE_GRE],
group='AGENT')
with testtools.ExpectedException(ValueError):
- ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ self.mod_agent.create_agent_config_map(cfg.CONF)
cfg.CONF.set_override('tunnel_types', [p_const.TYPE_VXLAN],
group='AGENT')
with testtools.ExpectedException(ValueError):
- ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ self.mod_agent.create_agent_config_map(cfg.CONF)
def test_create_agent_config_map_fails_no_local_ip(self):
# An ip address is required for tunneling but there is no default
cfg.CONF.set_override('tunnel_types', [p_const.TYPE_VXLAN],
group='AGENT')
with testtools.ExpectedException(ValueError):
- ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ self.mod_agent.create_agent_config_map(cfg.CONF)
def test_create_agent_config_map_fails_for_invalid_tunnel_type(self):
cfg.CONF.set_override('tunnel_types', ['foobar'], group='AGENT')
with testtools.ExpectedException(ValueError):
- ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ self.mod_agent.create_agent_config_map(cfg.CONF)
def test_create_agent_config_map_multiple_tunnel_types(self):
cfg.CONF.set_override('local_ip', '10.10.10.10', group='OVS')
cfg.CONF.set_override('tunnel_types', [p_const.TYPE_GRE,
p_const.TYPE_VXLAN], group='AGENT')
- cfgmap = ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ cfgmap = self.mod_agent.create_agent_config_map(cfg.CONF)
self.assertEqual(cfgmap['tunnel_types'],
[p_const.TYPE_GRE, p_const.TYPE_VXLAN])
# Verify setting only enable_tunneling will default tunnel_type to GRE
cfg.CONF.set_override('enable_distributed_routing', True,
group='AGENT')
- cfgmap = ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ cfgmap = self.mod_agent.create_agent_config_map(cfg.CONF)
self.assertEqual(cfgmap['enable_distributed_routing'], True)
-class TestOvsNeutronAgent(base.BaseTestCase):
+class TestOvsNeutronAgent(object):
def setUp(self):
super(TestOvsNeutronAgent, self).setUp()
group='SECURITYGROUP')
cfg.CONF.set_default('quitting_rpc_timeout', 10, 'AGENT')
cfg.CONF.set_default('prevent_arp_spoofing', False, 'AGENT')
- kwargs = ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ kwargs = self.mod_agent.create_agent_config_map(cfg.CONF)
class MockFixedIntervalLoopingCall(object):
def __init__(self, f):
self.f()
with contextlib.nested(
- mock.patch('neutron.plugins.openvswitch.agent.ovs_neutron_agent.'
- 'OVSNeutronAgent.setup_integration_br'),
- mock.patch('neutron.plugins.openvswitch.agent.ovs_neutron_agent.'
- 'OVSNeutronAgent.setup_ancillary_bridges',
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
+ 'setup_integration_br'),
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
+ 'setup_ancillary_bridges',
return_value=[]),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'create'),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'set_secure_mode'),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'get_local_port_mac',
- return_value='00:00:00:00:00:01'),
mock.patch('neutron.agent.linux.utils.get_interface_mac',
return_value='00:00:00:00:00:01'),
mock.patch('neutron.agent.common.ovs_lib.BaseOVS.get_bridges'),
new=MockFixedIntervalLoopingCall),
mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
'get_vif_ports', return_value=[])):
- self.agent = ovs_neutron_agent.OVSNeutronAgent(**kwargs)
+ self.agent = self.mod_agent.OVSNeutronAgent(self._bridge_classes(),
+ **kwargs)
# set back to true because initial report state will succeed due
# to mocked out RPC calls
self.agent.use_call = True
- self.agent.tun_br = mock.Mock()
+ self.agent.tun_br = self.br_tun_cls(br_name='br-tun')
self.agent.sg_agent = mock.Mock()
def _mock_port_bound(self, ofport=None, new_local_vlan=None,
'ip_address': '1.1.1.1'}]
if old_local_vlan is not None:
self.agent.local_vlan_map[net_uuid] = (
- ovs_neutron_agent.LocalVLANMapping(
+ self.mod_agent.LocalVLANMapping(
old_local_vlan, None, None, None))
- with contextlib.nested(
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'set_db_attribute', return_value=True),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'db_get_val', return_value={}),
- mock.patch.object(self.agent.int_br, 'delete_flows')
- ) as (set_ovs_db_func, get_ovs_db_func, delete_flows_func):
+ with mock.patch.object(self.agent, 'int_br', autospec=True) as int_br:
+ int_br.db_get_val.return_value = {}
+ int_br.set_db_attribute.return_value = True
self.agent.port_bound(port, net_uuid, 'local', None, None,
fixed_ips, "compute:None", False)
vlan_mapping = {'net_uuid': net_uuid,
'network_type': 'local',
'physical_network': None,
'segmentation_id': None}
- set_ovs_db_func.assert_called_once_with(
+ int_br.set_db_attribute.assert_called_once_with(
"Port", mock.ANY, "other_config", vlan_mapping)
def test_check_agent_configurations_for_dvr_raises(self):
def _test_port_dead(self, cur_tag=None):
port = mock.Mock()
port.ofport = 1
- with contextlib.nested(
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'set_db_attribute', return_value=True),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'db_get_val', return_value=cur_tag),
- mock.patch.object(self.agent.int_br, 'add_flow')
- ) as (set_ovs_db_func, get_ovs_db_func, add_flow_func):
+ with mock.patch.object(self.agent, 'int_br') as int_br:
+ int_br.db_get_val.return_value = cur_tag
self.agent.port_dead(port)
- get_ovs_db_func.assert_called_once_with("Port", mock.ANY, "tag")
- if cur_tag == ovs_neutron_agent.DEAD_VLAN_TAG:
- self.assertFalse(set_ovs_db_func.called)
- self.assertFalse(add_flow_func.called)
+ if cur_tag == self.mod_agent.DEAD_VLAN_TAG:
+ self.assertFalse(int_br.set_db_attribute.called)
+ self.assertFalse(int_br.drop_port.called)
else:
- set_ovs_db_func.assert_called_once_with(
- "Port", mock.ANY, "tag", ovs_neutron_agent.DEAD_VLAN_TAG)
- add_flow_func.assert_called_once_with(
- priority=2, in_port=port.ofport, actions="drop")
+ int_br.assert_has_calls([
+ mock.call.set_db_attribute("Port", mock.ANY, "tag",
+ self.mod_agent.DEAD_VLAN_TAG),
+ mock.call.drop_port(in_port=port.ofport),
+ ])
def test_port_dead(self):
self._test_port_dead()
def test_port_dead_with_port_already_dead(self):
- self._test_port_dead(ovs_neutron_agent.DEAD_VLAN_TAG)
+ self._test_port_dead(self.mod_agent.DEAD_VLAN_TAG)
def mock_scan_ports(self, vif_port_set=None, registered_ports=None,
updated_ports=None, port_tags_dict=None):
self.assertEqual(expected, actual)
def test_update_ports_returns_changed_vlan(self):
- br = ovs_lib.OVSBridge('br-int')
+ br = self.br_int_cls('br-int')
mac = "ca:fe:de:ad:be:ef"
port = ovs_lib.VifPort(1, 1, 1, mac, br)
- lvm = ovs_neutron_agent.LocalVLANMapping(
+ lvm = self.mod_agent.LocalVLANMapping(
1, '1', None, 1, {port.vif_id: port})
local_vlan_map = {'1': lvm}
vif_port_set = set([1, 3])
added=set([3]), current=vif_port_set,
removed=set([2]), updated=set([1])
)
- with mock.patch.dict(self.agent.local_vlan_map, local_vlan_map):
+ with contextlib.nested(
+ mock.patch.dict(self.agent.local_vlan_map, local_vlan_map),
+ mock.patch.object(self.agent, 'tun_br', autospec=True),
+ ):
actual = self.mock_scan_ports(
vif_port_set, registered_ports, port_tags_dict=port_tags_dict)
self.assertEqual(expected, actual)
mock.patch.object(self.agent.int_br, 'get_vif_port_by_id',
return_value=mock.Mock())):
self.assertRaises(
- ovs_neutron_agent.DeviceListRetrievalError,
+ self.mod_agent.DeviceListRetrievalError,
self.agent.treat_devices_added_or_updated, [{}], False)
def _mock_treat_devices_added_updated(self, details, port, func_name):
mock.patch.object(ip_lib, "device_exists"),
mock.patch.object(sys, "exit"),
mock.patch.object(utils, "execute"),
- mock.patch.object(ovs_lib.OVSBridge, "remove_all_flows"),
- mock.patch.object(ovs_lib.OVSBridge, "add_flow"),
- mock.patch.object(ovs_lib.OVSBridge, "add_patch_port"),
- mock.patch.object(ovs_lib.OVSBridge, "delete_port"),
- mock.patch.object(ovs_lib.OVSBridge, "set_db_attribute"),
- mock.patch.object(self.agent.int_br, "add_flow"),
- mock.patch.object(self.agent.int_br, "add_patch_port"),
- mock.patch.object(self.agent.int_br, "delete_port"),
- mock.patch.object(self.agent.int_br, "set_db_attribute"),
- ) as (devex_fn, sysexit_fn, utilsexec_fn, remflows_fn, ovs_add_flow_fn,
- ovs_addpatch_port_fn, ovs_delport_fn, ovs_set_attr_fn,
- br_add_flow_fn, br_addpatch_port_fn, br_delport_fn,
- br_set_attr_fn):
+ mock.patch.object(self.agent, 'br_phys_cls'),
+ mock.patch.object(self.agent, 'int_br'),
+ ) as (devex_fn, sysexit_fn, utilsexec_fn,
+ phys_br_cls, int_br):
devex_fn.return_value = True
parent = mock.MagicMock()
- parent.attach_mock(ovs_addpatch_port_fn, 'phy_add_patch_port')
- parent.attach_mock(ovs_add_flow_fn, 'phy_add_flow')
- parent.attach_mock(ovs_set_attr_fn, 'phy_set_attr')
- parent.attach_mock(br_addpatch_port_fn, 'int_add_patch_port')
- parent.attach_mock(br_add_flow_fn, 'int_add_flow')
- parent.attach_mock(br_set_attr_fn, 'int_set_attr')
-
- ovs_addpatch_port_fn.return_value = "phy_ofport"
- br_addpatch_port_fn.return_value = "int_ofport"
+ phys_br = phys_br_cls()
+ parent.attach_mock(phys_br_cls, 'phys_br_cls')
+ parent.attach_mock(phys_br, 'phys_br')
+ parent.attach_mock(int_br, 'int_br')
+ phys_br.add_patch_port.return_value = "phy_ofport"
+ int_br.add_patch_port.return_value = "int_ofport"
self.agent.setup_physical_bridges({"physnet1": "br-eth"})
expected_calls = [
- mock.call.phy_add_flow(priority=1, actions='normal'),
- mock.call.int_add_patch_port('int-br-eth',
- constants.NONEXISTENT_PEER),
- mock.call.phy_add_patch_port('phy-br-eth',
- constants.NONEXISTENT_PEER),
- mock.call.int_add_flow(priority=2, in_port='int_ofport',
- actions='drop'),
- mock.call.phy_add_flow(priority=2, in_port='phy_ofport',
- actions='drop'),
- mock.call.int_set_attr('Interface', 'int-br-eth',
- 'options:peer', 'phy-br-eth'),
- mock.call.phy_set_attr('Interface', 'phy-br-eth',
- 'options:peer', 'int-br-eth'),
-
+ mock.call.phys_br_cls('br-eth'),
+ mock.call.phys_br.setup_controllers(mock.ANY),
+ mock.call.phys_br.setup_default_table(),
+ mock.call.int_br.delete_port('int-br-eth'),
+ mock.call.phys_br.delete_port('phy-br-eth'),
+ mock.call.int_br.add_patch_port('int-br-eth',
+ constants.NONEXISTENT_PEER),
+ mock.call.phys_br.add_patch_port('phy-br-eth',
+ constants.NONEXISTENT_PEER),
+ mock.call.int_br.drop_port(in_port='int_ofport'),
+ mock.call.phys_br.drop_port(in_port='phy_ofport'),
+ mock.call.int_br.set_db_attribute('Interface', 'int-br-eth',
+ 'options:peer',
+ 'phy-br-eth'),
+ mock.call.phys_br.set_db_attribute('Interface', 'phy-br-eth',
+ 'options:peer',
+ 'int-br-eth'),
]
parent.assert_has_calls(expected_calls)
self.assertEqual(self.agent.int_ofports["physnet1"],
mock.patch.object(ip_lib, "device_exists"),
mock.patch.object(sys, "exit"),
mock.patch.object(utils, "execute"),
- mock.patch.object(ovs_lib.OVSBridge, "remove_all_flows"),
- mock.patch.object(ovs_lib.OVSBridge, "add_flow"),
- mock.patch.object(ovs_lib.OVSBridge, "add_port"),
- mock.patch.object(ovs_lib.OVSBridge, "delete_port"),
- mock.patch.object(self.agent.int_br, "add_port"),
- mock.patch.object(self.agent.int_br, "delete_port"),
+ mock.patch.object(self.agent, 'br_phys_cls'),
+ mock.patch.object(self.agent, 'int_br'),
mock.patch.object(ip_lib.IPWrapper, "add_veth"),
mock.patch.object(ip_lib.IpLinkCommand, "delete"),
mock.patch.object(ip_lib.IpLinkCommand, "set_up"),
mock.patch.object(ip_lib.IpLinkCommand, "set_mtu"),
mock.patch.object(ovs_lib.BaseOVS, "get_bridges")
- ) as (devex_fn, sysexit_fn, utilsexec_fn, remflows_fn, ovs_addfl_fn,
- ovs_addport_fn, ovs_delport_fn, br_addport_fn, br_delport_fn,
+ ) as (devex_fn, sysexit_fn, utilsexec_fn, phys_br_cls, int_br,
addveth_fn, linkdel_fn, linkset_fn, linkmtu_fn, get_br_fn):
devex_fn.return_value = True
parent = mock.MagicMock()
parent.attach_mock(addveth_fn, 'add_veth')
addveth_fn.return_value = (ip_lib.IPDevice("int-br-eth1"),
ip_lib.IPDevice("phy-br-eth1"))
- ovs_addport_fn.return_value = "phys_veth_ofport"
- br_addport_fn.return_value = "int_veth_ofport"
+ phys_br = phys_br_cls()
+ phys_br.add_port.return_value = "phys_veth_ofport"
+ int_br.add_port.return_value = "int_veth_ofport"
get_br_fn.return_value = ["br-eth"]
self.agent.setup_physical_bridges({"physnet1": "br-eth"})
expected_calls = [mock.call.link_delete(),
with contextlib.nested(
mock.patch.object(self.agent.int_br, "add_patch_port",
return_value=1),
- mock.patch.object(self.agent.tun_br, "add_patch_port",
- return_value=2),
- mock.patch.object(self.agent.tun_br, "remove_all_flows"),
- mock.patch.object(self.agent.tun_br, "add_flow"),
- mock.patch.object(ovs_lib, "OVSBridge"),
- mock.patch.object(self.agent.tun_br, "reset_bridge"),
+ mock.patch.object(self.agent, 'tun_br', autospec=True),
mock.patch.object(sys, "exit")
- ) as (intbr_patch_fn, tunbr_patch_fn, remove_all_fn,
- add_flow_fn, ovs_br_fn, reset_br_fn, exit_fn):
+ ) as (intbr_patch_fn, tun_br, exit_fn):
+ tun_br.add_patch_port.return_value = 2
self.agent.reset_tunnel_br(None)
self.agent.setup_tunnel_br()
self.assertTrue(intbr_patch_fn.called)
[l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1),
n_const.FLOODING_ENTRY]}}}
- class ActionMatcher(object):
- def __init__(self, action_str):
- self.ordered = self.order_ports(action_str)
-
- def order_ports(self, action_str):
- halves = action_str.split('output:')
- ports = sorted(halves.pop().split(','))
- halves.append(','.join(ports))
- return 'output:'.join(halves)
-
- def __eq__(self, other):
- return self.ordered == self.order_ports(other)
-
with contextlib.nested(
- 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 (deferred_fn, do_action_flows_fn, add_tun_fn):
- deferred_fn.return_value = ovs_lib.DeferredOVSBridge(
- self.agent.tun_br)
+ mock.patch.object(self.agent, 'tun_br', autospec=True),
+ mock.patch.object(self.agent, '_setup_tunnel_port', autospec=True),
+ ) as (tun_br, add_tun_fn):
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)})
+ deferred_br_call = mock.call.deferred().__enter__()
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=ActionMatcher('strip_vlan,'
- 'set_tunnel:seg1,output:1,2'))]),
+ deferred_br_call.install_arp_responder('vlan1', FAKE_IP1,
+ FAKE_MAC),
+ deferred_br_call.install_unicast_to_tun('vlan1', 'seg1', '2',
+ FAKE_MAC),
+ deferred_br_call.install_flood_to_tun('vlan1', 'seg1',
+ set(['1', '2'])),
]
- do_action_flows_fn.assert_has_calls(expected_calls)
+ tun_br.assert_has_calls(expected_calls)
def test_fdb_del_flows(self):
self._prepare_l2_pop_ofports()
{'2.2.2.2':
[l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1),
n_const.FLOODING_ENTRY]}}}
- with contextlib.nested(
- 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)
+ with mock.patch.object(self.agent, 'tun_br', autospec=True) as br_tun:
self.agent.fdb_remove(None, fdb_entry)
+ deferred_br_call = mock.call.deferred().__enter__()
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')]),
+ mock.call.deferred(),
+ mock.call.deferred().__enter__(),
+ deferred_br_call.delete_arp_responder('vlan2', FAKE_IP1),
+ deferred_br_call.delete_unicast_to_tun('vlan2', FAKE_MAC),
+ deferred_br_call.install_flood_to_tun('vlan2', 'seg2',
+ set(['1'])),
+ deferred_br_call.delete_port('gre-02020202'),
+ deferred_br_call.cleanup_tunnel_port('2'),
+ mock.call.deferred().__exit__(None, None, None),
]
- do_action_flows_fn.assert_has_calls(expected_calls)
+ br_tun.assert_has_calls(expected_calls)
def test_fdb_add_port(self):
self._prepare_l2_pop_ofports()
'ports': {'1.1.1.1': [l2pop_rpc.PortInfo(FAKE_MAC,
FAKE_IP1)]}}}
with contextlib.nested(
- 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', autospec=True),
mock.patch.object(self.agent, '_setup_tunnel_port')
- ) 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
+ ) as (tun_br, add_tun_fn):
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(add_tun_fn.called)
fdb_entry['net1']['ports']['10.10.10.10'] = [
l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1)]
self.agent.fdb_add(None, fdb_entry)
+ deferred_br = tun_br.deferred().__enter__()
add_tun_fn.assert_called_with(
deferred_br, 'gre-0a0a0a0a', '10.10.10.10', 'gre')
'ports': {'2.2.2.2': [n_const.FLOODING_ENTRY]}}}
with contextlib.nested(
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 (deferred_fn, do_action_flows_fn, delete_port_fn):
- deferred_br = ovs_lib.DeferredOVSBridge(self.agent.tun_br)
- deferred_fn.return_value = deferred_br
+ mock.patch.object(self.agent.tun_br, 'delete_port'),
+ ) as (defer_fn, delete_port_fn):
self.agent.fdb_remove(None, fdb_entry)
- delete_port_fn.assert_called_once_with('gre-02020202')
+ deferred_br = defer_fn().__enter__()
+ deferred_br.delete_port.assert_called_once_with('gre-02020202')
+ self.assertFalse(delete_port_fn.called)
def test_fdb_update_chg_ip(self):
self._prepare_l2_pop_ofports()
{'agent_ip':
{'before': [l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1)],
'after': [l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP2)]}}}}
- with contextlib.nested(
- 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
+ with mock.patch.object(self.agent.tun_br, 'deferred') as deferred_fn:
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)})
- 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))
+ deferred_br = deferred_fn().__enter__()
+ deferred_br.assert_has_calls([
+ mock.call.install_arp_responder('vlan1', FAKE_IP2, FAKE_MAC),
+ mock.call.delete_arp_responder('vlan1', FAKE_IP1)
+ ])
def test_del_fdb_flow_idempotency(self):
lvm = mock.Mock()
self._prepare_l2_pop_ofports()
self.agent.l2_pop = True
self.agent.enable_tunneling = True
- with mock.patch.object(
- self.agent.tun_br, 'cleanup_tunnel_port'
- ) as clean_tun_fn:
+ with mock.patch.object(self.agent, 'tun_br', autospec=True) as tun_br:
self.agent.reclaim_local_vlan('net1')
- self.assertFalse(clean_tun_fn.called)
+ self.assertFalse(tun_br.cleanup_tunnel_port.called)
def test_recl_lv_port_to_remove(self):
self._prepare_l2_pop_ofports()
self.agent.l2_pop = True
self.agent.enable_tunneling = True
- with contextlib.nested(
- mock.patch.object(self.agent.tun_br, 'delete_port'),
- mock.patch.object(self.agent.tun_br, 'delete_flows')
- ) as (del_port_fn, del_flow_fn):
+ with mock.patch.object(self.agent, 'tun_br', autospec=True) as tun_br:
self.agent.reclaim_local_vlan('net2')
- del_port_fn.assert_called_once_with('gre-02020202')
+ tun_br.delete_port.assert_called_once_with('gre-02020202')
def test_daemon_loop_uses_polling_manager(self):
with mock.patch(
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
return_value=ovs_lib.INVALID_OFPORT),
- mock.patch.object(ovs_neutron_agent.LOG, 'error')
+ mock.patch.object(self.mod_agent.LOG, 'error')
) as (add_tunnel_port_fn, log_error_fn):
ofport = self.agent._setup_tunnel_port(
self.agent.tun_br, 'gre-1', 'remote_ip', p_const.TYPE_GRE)
with contextlib.nested(
mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
return_value=ovs_lib.INVALID_OFPORT),
- mock.patch.object(ovs_neutron_agent.LOG, 'error')
+ mock.patch.object(self.mod_agent.LOG, 'error')
) as (add_tunnel_port_fn, log_error_fn):
self.agent.dont_fragment = False
ofport = self.agent._setup_tunnel_port(
with contextlib.nested(
mock.patch.object(async_process.AsyncProcess, "_spawn"),
mock.patch.object(log.KeywordArgumentAdapter, 'exception'),
- mock.patch.object(ovs_neutron_agent.OVSNeutronAgent,
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
'scan_ports'),
- mock.patch.object(ovs_neutron_agent.OVSNeutronAgent,
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
'process_network_ports'),
- mock.patch.object(ovs_neutron_agent.OVSNeutronAgent,
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
'check_ovs_status'),
- mock.patch.object(ovs_neutron_agent.OVSNeutronAgent,
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
'setup_integration_br'),
- mock.patch.object(ovs_neutron_agent.OVSNeutronAgent,
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
'setup_physical_bridges'),
mock.patch.object(time, 'sleep'),
- mock.patch.object(ovs_neutron_agent.OVSNeutronAgent,
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
'update_stale_ofport_rules')
) as (spawn_fn, log_exception, scan_ports, process_network_ports,
check_ovs_status, setup_int_br, setup_phys_br, time_sleep,
# all of this is required just to get to the part of
# treat_devices_added_or_updated that checks the prevent_arp_spoofing
# flag
- self.agent.int_br = mock.Mock()
+ self.agent.int_br = mock.create_autospec(self.agent.int_br)
self.agent.treat_vif_port = mock.Mock()
self.agent.get_vif_port_by_id = mock.Mock(return_value=FakeVif())
self.agent.plugin_rpc = mock.Mock()
self.assertFalse(self.agent.setup_arp_spoofing_protection.called)
def test_arp_spoofing_port_security_disabled(self):
- int_br = mock.Mock()
+ int_br = mock.create_autospec(self.agent.int_br)
self.agent.setup_arp_spoofing_protection(
int_br, FakeVif(), {'port_security_enabled': False})
- self.assertFalse(int_br.add_flows.called)
+ self.assertTrue(int_br.delete_arp_spoofing_protection.called)
+ self.assertFalse(int_br.install_arp_spoofing_protection.called)
def test_arp_spoofing_basic_rule_setup(self):
vif = FakeVif()
fake_details = {'fixed_ips': []}
self.agent.prevent_arp_spoofing = True
- int_br = mock.Mock()
+ int_br = mock.create_autospec(self.agent.int_br)
self.agent.setup_arp_spoofing_protection(int_br, vif, fake_details)
- int_br.delete_flows.assert_has_calls(
- [mock.call(table=mock.ANY, in_port=vif.ofport)])
- # make sure redirect into spoof table is installed
- int_br.add_flow.assert_any_call(
- table=constants.LOCAL_SWITCHING, in_port=vif.ofport,
- proto='arp', actions=mock.ANY, priority=10)
- # make sure drop rule for replies is installed
- int_br.add_flow.assert_any_call(
- table=constants.ARP_SPOOF_TABLE,
- proto='arp', actions='DROP', priority=mock.ANY)
+ self.assertEqual(
+ [mock.call(port=vif.ofport)],
+ int_br.delete_arp_spoofing_protection.mock_calls)
+ self.assertEqual(
+ [mock.call(ip_addresses=set(), port=vif.ofport)],
+ int_br.install_arp_spoofing_protection.mock_calls)
def test_arp_spoofing_fixed_and_allowed_addresses(self):
vif = FakeVif()
{'ip_address': '192.168.44.103/32'}]
}
self.agent.prevent_arp_spoofing = True
- int_br = mock.Mock()
+ int_br = mock.create_autospec(self.agent.int_br)
self.agent.setup_arp_spoofing_protection(int_br, vif, fake_details)
# make sure all addresses are allowed
- for addr in ('192.168.44.100', '192.168.44.101', '192.168.44.102/32',
- '192.168.44.103/32'):
- int_br.add_flow.assert_any_call(
- table=constants.ARP_SPOOF_TABLE, in_port=vif.ofport,
- proto='arp', actions='NORMAL', arp_spa=addr, priority=mock.ANY)
+ addresses = {'192.168.44.100', '192.168.44.101', '192.168.44.102/32',
+ '192.168.44.103/32'}
+ self.assertEqual(
+ [mock.call(port=vif.ofport, ip_addresses=addresses)],
+ int_br.install_arp_spoofing_protection.mock_calls)
def test__get_ofport_moves(self):
previous = {'port1': 1, 'port2': 2}
self.agent.int_br.get_vif_port_to_ofport_map.return_value = newmap
self.agent.update_stale_ofport_rules()
# rules matching port 1 should have been deleted
- self.assertEqual(self.agent.int_br.delete_flows.mock_calls,
- [mock.call(in_port=1)])
+ self.assertEqual(
+ [mock.call(port=1)],
+ self.agent.int_br.delete_arp_spoofing_protection.mock_calls)
# make sure the state was updated with the new map
self.assertEqual(self.agent.vifname_to_ofport_map, newmap)
def add_new_vlan_mapping(*args, **kwargs):
self.agent.local_vlan_map['bar'] = (
- ovs_neutron_agent.LocalVLANMapping(1, 2, 3, 4))
+ self.mod_agent.LocalVLANMapping(1, 2, 3, 4))
bridge = mock.Mock()
tunnel_type = 'vxlan'
self.agent.tun_br_ofports = {tunnel_type: dict()}
self.agent.l2_pop = False
self.agent.local_vlan_map = {
- 'foo': ovs_neutron_agent.LocalVLANMapping(4, tunnel_type, 2, 1)}
- bridge.mod_flow.side_effect = add_new_vlan_mapping
- with mock.patch('neutron.plugins.openvswitch.agent.ovs_neutron_agent.'
- '_ofport_set_to_str', return_value=True):
- self.agent._setup_tunnel_port(bridge, 1, 2,
- tunnel_type=tunnel_type)
+ 'foo': self.mod_agent.LocalVLANMapping(4, tunnel_type, 2, 1)}
+ bridge.install_flood_to_tun.side_effect = add_new_vlan_mapping
+ self.agent._setup_tunnel_port(bridge, 1, 2, tunnel_type=tunnel_type)
self.assertIn('bar', self.agent.local_vlan_map)
-class AncillaryBridgesTest(base.BaseTestCase):
+class TestOvsNeutronAgentOFCtl(TestOvsNeutronAgent,
+ ovs_test_base.OVSOFCtlTestBase):
+ pass
+
+
+class AncillaryBridgesTest(object):
def setUp(self):
super(AncillaryBridgesTest, self).setUp()
'neutron.agent.firewall.NoopFirewallDriver',
group='SECURITYGROUP')
cfg.CONF.set_override('report_interval', 0, 'AGENT')
- self.kwargs = ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ self.kwargs = self.mod_agent.create_agent_config_map(cfg.CONF)
def _test_ancillary_bridges(self, bridges, ancillary):
device_ids = ancillary[:]
return None
with contextlib.nested(
- mock.patch('neutron.plugins.openvswitch.agent.ovs_neutron_agent.'
- 'OVSNeutronAgent.setup_integration_br'),
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
+ 'setup_integration_br'),
mock.patch('neutron.agent.linux.utils.get_interface_mac',
return_value='00:00:00:00:00:01'),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'get_local_port_mac',
- return_value='00:00:00:00:00:01'),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'set_secure_mode'),
mock.patch('neutron.agent.common.ovs_lib.BaseOVS.get_bridges',
return_value=bridges),
mock.patch('neutron.agent.common.ovs_lib.BaseOVS.'
side_effect=pullup_side_effect),
mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
'get_vif_ports', return_value=[])):
- self.agent = ovs_neutron_agent.OVSNeutronAgent(**self.kwargs)
+ self.agent = self.mod_agent.OVSNeutronAgent(self._bridge_classes(),
+ **self.kwargs)
self.assertEqual(len(ancillary), len(self.agent.ancillary_brs))
if ancillary:
bridges = [br.br_name for br in self.agent.ancillary_brs]
self._test_ancillary_bridges(bridges, ['br-ex1', 'br-ex2'])
-class TestOvsDvrNeutronAgent(base.BaseTestCase):
+class AncillaryBridgesTestOFCtl(AncillaryBridgesTest,
+ ovs_test_base.OVSOFCtlTestBase):
+ pass
+
+
+class TestOvsDvrNeutronAgent(object):
def setUp(self):
super(TestOvsDvrNeutronAgent, self).setUp()
cfg.CONF.set_default('firewall_driver',
'neutron.agent.firewall.NoopFirewallDriver',
group='SECURITYGROUP')
- kwargs = ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ kwargs = self.mod_agent.create_agent_config_map(cfg.CONF)
class MockFixedIntervalLoopingCall(object):
def __init__(self, f):
self.f()
with contextlib.nested(
- mock.patch('neutron.plugins.openvswitch.agent.ovs_neutron_agent.'
- 'OVSNeutronAgent.setup_integration_br'),
- mock.patch('neutron.plugins.openvswitch.agent.ovs_neutron_agent.'
- 'OVSNeutronAgent.setup_ancillary_bridges',
- return_value=[]),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'create'),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'set_secure_mode'),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'get_local_port_mac',
- return_value='00:00:00:00:00:01'),
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
+ 'setup_integration_br'),
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
+ 'setup_ancillary_bridges',
+ return_value=[]),
mock.patch('neutron.agent.linux.utils.get_interface_mac',
return_value='00:00:00:00:00:01'),
mock.patch('neutron.agent.common.ovs_lib.BaseOVS.get_bridges'),
new=MockFixedIntervalLoopingCall),
mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
'get_vif_ports', return_value=[])):
- self.agent = ovs_neutron_agent.OVSNeutronAgent(**kwargs)
+ self.agent = self.mod_agent.OVSNeutronAgent(self._bridge_classes(),
+ **kwargs)
# set back to true because initial report state will succeed due
# to mocked out RPC calls
self.agent.use_call = True
- self.agent.tun_br = mock.Mock()
+ self.agent.tun_br = self.br_tun_cls(br_name='br-tun')
self.agent.sg_agent = mock.Mock()
def _setup_for_dvr_test(self, ofport=10):
self._compute_fixed_ips = [{'subnet_id': 'my-subnet-uuid',
'ip_address': '1.1.1.3'}]
+ @staticmethod
+ def _expected_port_bound(port, lvid):
+ return [
+ mock.call.db_get_val('Port', port.port_name, 'other_config'),
+ mock.call.set_db_attribute('Port', port.port_name, 'other_config',
+ mock.ANY),
+ ]
+
+ def _expected_install_dvr_process(self, lvid, port, ip_version,
+ gateway_ip, gateway_mac):
+ if ip_version == 4:
+ ipvx_calls = [
+ mock.call.install_dvr_process_ipv4(
+ vlan_tag=lvid,
+ gateway_ip=gateway_ip),
+ ]
+ else:
+ ipvx_calls = [
+ mock.call.install_dvr_process_ipv6(
+ vlan_tag=lvid,
+ gateway_mac=gateway_mac),
+ ]
+ return ipvx_calls + [
+ mock.call.install_dvr_process(
+ vlan_tag=lvid,
+ dvr_mac_address=self.agent.dvr_agent.dvr_mac_address,
+ vif_mac=port.vif_mac,
+ ),
+ ]
+
def _test_port_bound_for_dvr_on_vlan_network(self, device_owner,
ip_version=4):
self._setup_for_dvr_test()
physical_network = self._physical_network
segmentation_id = self._segmentation_id
network_type = p_const.TYPE_VLAN
+ int_br = mock.create_autospec(self.agent.int_br)
+ tun_br = mock.create_autospec(self.agent.tun_br)
+ phys_br = mock.create_autospec(self.br_phys_cls('br-phys'))
+ int_br.set_db_attribute.return_value = True
+ int_br.db_get_val.return_value = {}
with contextlib.nested(
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'set_db_attribute',
- return_value=True),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'db_get_val',
- return_value={})):
- with contextlib.nested(
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_subnet_for_dvr',
- return_value={
- 'gateway_ip': gateway_ip,
- 'cidr': cidr,
- 'ip_version': ip_version,
- 'gateway_mac': gateway_mac}),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_ports_on_host_by_subnet',
- return_value=[]),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'get_vif_port_by_id',
- return_value=self._port),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows'),
- mock.patch.object(
- self.agent.dvr_agent.phys_brs[physical_network],
- 'add_flow'),
- mock.patch.object(
- self.agent.dvr_agent.phys_brs[physical_network],
- 'delete_flows')
- ) as (get_subnet_fn, get_cphost_fn,
- get_vif_fn, add_flow_int_fn,
- add_flow_tun_fn, delete_flows_tun_fn, add_flow_phys_fn,
- delete_flows_phys_fn):
- self.agent.port_bound(
- self._port, self._net_uuid, network_type,
- physical_network, segmentation_id, self._fixed_ips,
- n_const.DEVICE_OWNER_DVR_INTERFACE, False)
- lvm = self.agent.local_vlan_map[self._net_uuid]
- phy_ofp = self.agent.dvr_agent.phys_ofports[physical_network]
- int_ofp = self.agent.dvr_agent.int_ofports[physical_network]
- expected_on_phys_br = [
- mock.call(table=constants.LOCAL_VLAN_TRANSLATION,
- priority=4,
- in_port=phy_ofp,
- dl_vlan=lvm.vlan,
- actions="mod_vlan_vid:%s,normal" %
- (lvm.segmentation_id)),
- mock.call(table=constants.DVR_PROCESS_VLAN,
- priority=2,
- dl_vlan=lvm.vlan,
- dl_dst=self._port.vif_mac,
- actions="drop"),
- mock.call(table=constants.DVR_PROCESS_VLAN,
- priority=1,
- dl_vlan=lvm.vlan,
- dl_src=self._port.vif_mac,
- actions="mod_dl_src:%s,resubmit(,%s)" %
- (self.agent.dvr_agent.dvr_mac_address,
- constants.LOCAL_VLAN_TRANSLATION))
- ]
- if ip_version == 4:
- expected_on_phys_br.insert(1, mock.call(
- proto='arp',
- nw_dst=gateway_ip, actions='drop',
- priority=3, table=constants.DVR_PROCESS_VLAN,
- dl_vlan=lvm.vlan))
- else:
- expected_on_phys_br.insert(1, mock.call(
- icmp_type=n_const.ICMPV6_TYPE_RA, proto='icmp6',
- dl_src=self._port.vif_mac, actions='drop',
- priority=3, table=constants.DVR_PROCESS_VLAN,
- dl_vlan=lvm.vlan))
- self.assertEqual(expected_on_phys_br,
- add_flow_phys_fn.call_args_list)
- self.agent.port_bound(self._compute_port, self._net_uuid,
- network_type, physical_network,
- segmentation_id,
- self._compute_fixed_ips,
- device_owner, False)
- expected_on_int_br = [
- mock.call(priority=3,
- in_port=int_ofp,
- dl_vlan=lvm.segmentation_id,
- actions="mod_vlan_vid:%s,normal" % lvm.vlan),
- mock.call(table=constants.DVR_TO_SRC_MAC_VLAN,
- priority=4,
- dl_dst=self._compute_port.vif_mac,
- dl_vlan=lvm.segmentation_id,
- actions="strip_vlan,mod_dl_src:%s,"
- "output:%s" %
- (gateway_mac,
- self._compute_port.ofport))
- ]
- self.assertEqual(expected_on_int_br,
- add_flow_int_fn.call_args_list)
- self.assertFalse(add_flow_tun_fn.called)
- self.assertFalse(delete_flows_tun_fn.called)
- self.assertFalse(delete_flows_phys_fn.called)
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_subnet_for_dvr',
+ return_value={
+ 'gateway_ip': gateway_ip,
+ 'cidr': cidr,
+ 'ip_version': ip_version,
+ 'gateway_mac': gateway_mac}),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_ports_on_host_by_subnet',
+ return_value=[]),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'get_vif_port_by_id',
+ return_value=self._port),
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
+ mock.patch.dict(self.agent.phys_brs,
+ {physical_network: phys_br}),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),
+ mock.patch.dict(self.agent.dvr_agent.phys_brs,
+ {physical_network: phys_br}),
+ ) as (get_subnet_fn, get_cphost_fn, get_vif_fn, _, _, _, _, _, _):
+ self.agent.port_bound(
+ self._port, self._net_uuid, network_type,
+ physical_network, segmentation_id, self._fixed_ips,
+ n_const.DEVICE_OWNER_DVR_INTERFACE, False)
+ phy_ofp = self.agent.dvr_agent.phys_ofports[physical_network]
+ int_ofp = self.agent.dvr_agent.int_ofports[physical_network]
+ lvid = self.agent.local_vlan_map[self._net_uuid].vlan
+ expected_on_phys_br = [
+ mock.call.provision_local_vlan(
+ port=phy_ofp,
+ lvid=lvid,
+ segmentation_id=segmentation_id,
+ distributed=True,
+ ),
+ ] + self._expected_install_dvr_process(
+ port=self._port,
+ lvid=lvid,
+ ip_version=ip_version,
+ gateway_ip=gateway_ip,
+ gateway_mac=gateway_mac)
+ expected_on_int_br = [
+ mock.call.provision_local_vlan(
+ port=int_ofp,
+ lvid=lvid,
+ segmentation_id=segmentation_id,
+ ),
+ ] + self._expected_port_bound(self._port, lvid)
+ self.assertEqual(expected_on_int_br, int_br.mock_calls)
+ self.assertEqual([], tun_br.mock_calls)
+ self.assertEqual(expected_on_phys_br, phys_br.mock_calls)
+ int_br.reset_mock()
+ tun_br.reset_mock()
+ phys_br.reset_mock()
+ self.agent.port_bound(self._compute_port, self._net_uuid,
+ network_type, physical_network,
+ segmentation_id,
+ self._compute_fixed_ips,
+ device_owner, False)
+ expected_on_int_br = [
+ mock.call.install_dvr_to_src_mac(
+ network_type=network_type,
+ gateway_mac=gateway_mac,
+ dst_mac=self._compute_port.vif_mac,
+ dst_port=self._compute_port.ofport,
+ vlan_tag=segmentation_id,
+ ),
+ ] + self._expected_port_bound(self._compute_port, lvid)
+ self.assertEqual(expected_on_int_br, int_br.mock_calls)
+ self.assertFalse([], tun_br.mock_calls)
+ self.assertFalse([], phys_br.mock_calls)
def _test_port_bound_for_dvr_on_vxlan_network(self, device_owner,
ip_version=4):
self._compute_port.vif_mac = '77:88:99:00:11:22'
physical_network = self._physical_network
segmentation_id = self._segmentation_id
+ int_br = mock.create_autospec(self.agent.int_br)
+ tun_br = mock.create_autospec(self.agent.tun_br)
+ phys_br = mock.create_autospec(self.br_phys_cls('br-phys'))
+ int_br.set_db_attribute.return_value = True
+ int_br.db_get_val.return_value = {}
with contextlib.nested(
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'set_db_attribute',
- return_value=True),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'db_get_val',
- return_value={})):
- with contextlib.nested(
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_subnet_for_dvr',
- return_value={
- 'gateway_ip': gateway_ip,
- 'cidr': cidr,
- 'ip_version': ip_version,
- 'gateway_mac': gateway_mac}),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_ports_on_host_by_subnet',
- return_value=[]),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'get_vif_port_by_id',
- return_value=self._port),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows'),
- mock.patch.object(
- self.agent.dvr_agent.phys_brs[physical_network],
- 'add_flow'),
- mock.patch.object(
- self.agent.dvr_agent.phys_brs[physical_network],
- 'delete_flows')
- ) as (get_subnet_fn, get_cphost_fn,
- get_vif_fn, add_flow_int_fn,
- add_flow_tun_fn, delete_flows_tun_fn,
- add_flow_phys_fn, delete_flows_phys_fn):
- self.agent.port_bound(
- self._port, self._net_uuid, network_type,
- physical_network, segmentation_id, self._fixed_ips,
- n_const.DEVICE_OWNER_DVR_INTERFACE, False)
- lvm = self.agent.local_vlan_map[self._net_uuid]
- expected_on_tun_br = [
- mock.call(
- table=constants.TUN_TABLE['vxlan'],
- priority=1, tun_id=lvm.segmentation_id,
- actions="mod_vlan_vid:%s,"
- "resubmit(,%s)" %
- (lvm.vlan, constants.DVR_NOT_LEARN)),
- mock.call(
- table=constants.DVR_PROCESS, priority=2,
- dl_vlan=lvm.vlan,
- dl_dst=self._port.vif_mac,
- actions='drop'),
- mock.call(
- table=constants.DVR_PROCESS, priority=1,
- dl_vlan=lvm.vlan,
- dl_src=self._port.vif_mac,
- actions="mod_dl_src:%s,resubmit(,%s)" % (
- self.agent.dvr_agent.dvr_mac_address,
- constants.PATCH_LV_TO_TUN))]
- if ip_version == 4:
- expected_on_tun_br.insert(1, mock.call(
- proto='arp',
- nw_dst=gateway_ip, actions='drop',
- priority=3, table=constants.DVR_PROCESS,
- dl_vlan=lvm.vlan))
- else:
- expected_on_tun_br.insert(1, mock.call(
- icmp_type=n_const.ICMPV6_TYPE_RA,
- proto='icmp6',
- dl_src=self._port.vif_mac,
- actions='drop',
- priority=3, table=constants.DVR_PROCESS,
- dl_vlan=lvm.vlan))
- self.assertEqual(expected_on_tun_br,
- add_flow_tun_fn.call_args_list)
- self.agent.port_bound(self._compute_port, self._net_uuid,
- network_type, physical_network,
- segmentation_id,
- self._compute_fixed_ips,
- device_owner, False)
- expected_on_int_br = [
- mock.call(table=constants.DVR_TO_SRC_MAC, priority=4,
- dl_dst=self._compute_port.vif_mac,
- dl_vlan=lvm.vlan,
- actions="strip_vlan,mod_dl_src:%s,"
- "output:%s" %
- (gateway_mac, self._compute_port.ofport))
- ]
- self.assertEqual(expected_on_int_br,
- add_flow_int_fn.call_args_list)
- self.assertFalse(add_flow_phys_fn.called)
- self.assertFalse(add_flow_phys_fn.called)
- self.assertFalse(delete_flows_tun_fn.called)
- self.assertFalse(delete_flows_phys_fn.called)
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_subnet_for_dvr',
+ return_value={
+ 'gateway_ip': gateway_ip,
+ 'cidr': cidr,
+ 'ip_version': ip_version,
+ 'gateway_mac': gateway_mac}),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_ports_on_host_by_subnet',
+ return_value=[]),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'get_vif_port_by_id',
+ return_value=self._port),
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
+ mock.patch.dict(self.agent.phys_brs,
+ {physical_network: phys_br}),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),
+ mock.patch.dict(self.agent.dvr_agent.phys_brs,
+ {physical_network: phys_br}),
+ ) as (get_subnet_fn, get_cphost_fn, get_vif_fn, _, _, _, _, _, _):
+ self.agent.port_bound(
+ self._port, self._net_uuid, network_type,
+ physical_network, segmentation_id, self._fixed_ips,
+ n_const.DEVICE_OWNER_DVR_INTERFACE, False)
+ lvid = self.agent.local_vlan_map[self._net_uuid].vlan
+ expected_on_int_br = self._expected_port_bound(
+ self._port, lvid)
+ expected_on_tun_br = [
+ mock.call.provision_local_vlan(
+ network_type=network_type,
+ segmentation_id=segmentation_id,
+ lvid=lvid,
+ distributed=True),
+ ] + self._expected_install_dvr_process(
+ port=self._port,
+ lvid=lvid,
+ ip_version=ip_version,
+ gateway_ip=gateway_ip,
+ gateway_mac=gateway_mac)
+ self.assertEqual(expected_on_int_br, int_br.mock_calls)
+ self.assertEqual(expected_on_tun_br, tun_br.mock_calls)
+ self.assertEqual([], phys_br.mock_calls)
+ int_br.reset_mock()
+ tun_br.reset_mock()
+ phys_br.reset_mock()
+ self.agent.port_bound(self._compute_port, self._net_uuid,
+ network_type, physical_network,
+ segmentation_id,
+ self._compute_fixed_ips,
+ device_owner, False)
+ expected_on_int_br = [
+ mock.call.install_dvr_to_src_mac(
+ network_type=network_type,
+ gateway_mac=gateway_mac,
+ dst_mac=self._compute_port.vif_mac,
+ dst_port=self._compute_port.ofport,
+ vlan_tag=lvid,
+ ),
+ ] + self._expected_port_bound(self._compute_port, lvid)
+ self.assertEqual(expected_on_int_br, int_br.mock_calls)
+ self.assertEqual([], tun_br.mock_calls)
+ self.assertEqual([], phys_br.mock_calls)
def test_port_bound_for_dvr_with_compute_ports(self):
self._test_port_bound_for_dvr_on_vlan_network(
def test_port_bound_for_dvr_with_csnat_ports(self, ofport=10):
self._setup_for_dvr_test()
+ int_br = mock.create_autospec(self.agent.int_br)
+ tun_br = mock.create_autospec(self.agent.tun_br)
+ int_br.set_db_attribute.return_value = True
+ int_br.db_get_val.return_value = {}
with contextlib.nested(
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'set_db_attribute',
- return_value=True),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'db_get_val',
- return_value={})):
- with contextlib.nested(
- mock.patch.object(
- self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
- return_value={'gateway_ip': '1.1.1.1',
- 'cidr': '1.1.1.0/24',
- 'ip_version': 4,
- 'gateway_mac': 'aa:bb:cc:11:22:33'}),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_ports_on_host_by_subnet',
- return_value=[]),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'get_vif_port_by_id',
- return_value=self._port),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
- ) as (get_subnet_fn, get_cphost_fn,
- get_vif_fn, add_flow_int_fn,
- add_flow_tun_fn, delete_flows_tun_fn):
- self.agent.port_bound(
- self._port, self._net_uuid, 'vxlan',
- None, None, self._fixed_ips,
- n_const.DEVICE_OWNER_ROUTER_SNAT,
- False)
- self.assertTrue(add_flow_int_fn.called)
+ mock.patch.object(
+ self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
+ return_value={'gateway_ip': '1.1.1.1',
+ 'cidr': '1.1.1.0/24',
+ 'ip_version': 4,
+ 'gateway_mac': 'aa:bb:cc:11:22:33'}),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_ports_on_host_by_subnet',
+ return_value=[]),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'get_vif_port_by_id',
+ return_value=self._port),
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),
+ ) as (get_subnet_fn, get_cphost_fn, get_vif_fn, _, _, _, _):
+ self.agent.port_bound(
+ self._port, self._net_uuid, 'vxlan',
+ None, None, self._fixed_ips,
+ n_const.DEVICE_OWNER_ROUTER_SNAT,
+ False)
+ lvid = self.agent.local_vlan_map[self._net_uuid].vlan
+ expected_on_int_br = [
+ mock.call.install_dvr_to_src_mac(
+ network_type='vxlan',
+ gateway_mac='aa:bb:cc:11:22:33',
+ dst_mac=self._port.vif_mac,
+ dst_port=self._port.ofport,
+ vlan_tag=lvid,
+ ),
+ ] + self._expected_port_bound(self._port, lvid)
+ self.assertEqual(expected_on_int_br, int_br.mock_calls)
+ expected_on_tun_br = [
+ mock.call.provision_local_vlan(
+ network_type='vxlan',
+ lvid=lvid,
+ segmentation_id=None,
+ distributed=True,
+ ),
+ ]
+ self.assertEqual(expected_on_tun_br, tun_br.mock_calls)
def test_treat_devices_removed_for_dvr_interface(self, ofport=10):
self._test_treat_devices_removed_for_dvr_interface(ofport)
else:
gateway_ip = '2001:100::1'
cidr = '2001:100::0/64'
+ gateway_mac = 'aa:bb:cc:11:22:33'
+ int_br = mock.create_autospec(self.agent.int_br)
+ tun_br = mock.create_autospec(self.agent.tun_br)
+ int_br.set_db_attribute.return_value = True
+ int_br.db_get_val.return_value = {}
with contextlib.nested(
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'set_db_attribute',
- return_value=True),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'db_get_val',
- return_value={})):
- with contextlib.nested(
- mock.patch.object(
- self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
- return_value={'gateway_ip': gateway_ip,
- 'cidr': cidr,
- 'ip_version': ip_version,
- 'gateway_mac': 'aa:bb:cc:11:22:33'}),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_ports_on_host_by_subnet',
- return_value=[]),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'get_vif_port_by_id',
- return_value=self._port),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
- ) as (get_subnet_fn, get_cphost_fn,
- get_vif_fn, add_flow_int_fn,
- add_flow_tun_fn, delete_flows_tun_fn):
- self.agent.port_bound(
- self._port, self._net_uuid, 'vxlan',
- None, None, self._fixed_ips,
- n_const.DEVICE_OWNER_DVR_INTERFACE,
- False)
- self.assertTrue(add_flow_tun_fn.called)
-
+ mock.patch.object(
+ self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
+ return_value={'gateway_ip': gateway_ip,
+ 'cidr': cidr,
+ 'ip_version': ip_version,
+ 'gateway_mac': gateway_mac}),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_ports_on_host_by_subnet',
+ return_value=[]),
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'get_vif_port_by_id',
+ return_value=self._port),
+ ) as (get_subnet_fn, get_cphost_fn, _, _, _, _, get_vif_fn):
+ self.agent.port_bound(
+ self._port, self._net_uuid, 'vxlan',
+ None, None, self._fixed_ips,
+ n_const.DEVICE_OWNER_DVR_INTERFACE,
+ False)
+ lvid = self.agent.local_vlan_map[self._net_uuid].vlan
+ self.assertEqual(self._expected_port_bound(self._port, lvid),
+ int_br.mock_calls)
+ expected_on_tun_br = [
+ mock.call.provision_local_vlan(network_type='vxlan',
+ lvid=lvid, segmentation_id=None, distributed=True),
+ ] + self._expected_install_dvr_process(
+ port=self._port,
+ lvid=lvid,
+ ip_version=ip_version,
+ gateway_ip=gateway_ip,
+ gateway_mac=gateway_mac)
+ self.assertEqual(expected_on_tun_br, tun_br.mock_calls)
+
+ int_br.reset_mock()
+ tun_br.reset_mock()
with contextlib.nested(
mock.patch.object(self.agent, 'reclaim_local_vlan'),
mock.patch.object(self.agent.plugin_rpc, 'update_device_down',
return_value=None),
- mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
- mock.patch.object(self.agent.dvr_agent.tun_br,
- 'delete_flows')) as (reclaim_vlan_fn,
- update_dev_down_fn,
- delete_flows_int_fn,
- delete_flows_tun_fn):
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),
+ ) as (reclaim_vlan_fn, update_dev_down_fn, _, _, _, _):
self.agent.treat_devices_removed([self._port.vif_id])
if ip_version == 4:
- expected = [mock.call(
- proto='arp',
- nw_dst=gateway_ip,
- table=constants.DVR_PROCESS,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan))]
+ expected = [
+ mock.call.delete_dvr_process_ipv4(
+ vlan_tag=lvid,
+ gateway_ip=gateway_ip),
+ ]
else:
- expected = [mock.call(
- icmp_type=n_const.ICMPV6_TYPE_RA, proto='icmp6',
- dl_src='aa:bb:cc:11:22:33',
- table=constants.DVR_PROCESS,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan))]
+ expected = [
+ mock.call.delete_dvr_process_ipv6(
+ vlan_tag=lvid,
+ gateway_mac=gateway_mac),
+ ]
expected.extend([
- mock.call(
- table=constants.DVR_PROCESS,
- dl_dst=self._port.vif_mac,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan)),
- mock.call(
- table=constants.DVR_PROCESS,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan),
- dl_src=self._port.vif_mac)
+ mock.call.delete_dvr_process(
+ vlan_tag=lvid,
+ vif_mac=self._port.vif_mac),
])
- self.assertEqual(expected, delete_flows_tun_fn.call_args_list)
+ self.assertEqual([], int_br.mock_calls)
+ self.assertEqual(expected, tun_br.mock_calls)
def _test_treat_devices_removed_for_dvr(self, device_owner, ip_version=4):
self._setup_for_dvr_test()
else:
gateway_ip = '2001:100::1'
cidr = '2001:100::0/64'
+ gateway_mac = 'aa:bb:cc:11:22:33'
+ int_br = mock.create_autospec(self.agent.int_br)
+ tun_br = mock.create_autospec(self.agent.tun_br)
+ int_br.set_db_attribute.return_value = True
+ int_br.db_get_val.return_value = {}
with contextlib.nested(
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'set_db_attribute',
- return_value=True),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'db_get_val',
- return_value={})):
- with contextlib.nested(
- mock.patch.object(
- self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
- return_value={'gateway_ip': gateway_ip,
- 'cidr': cidr,
- 'ip_version': ip_version,
- 'gateway_mac': 'aa:bb:cc:11:22:33'}),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_ports_on_host_by_subnet',
- return_value=[]),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'get_vif_port_by_id',
- return_value=self._port),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
- ) as (get_subnet_fn, get_cphost_fn,
- get_vif_fn, add_flow_int_fn,
- add_flow_tun_fn, delete_flows_tun_fn):
- self.agent.port_bound(
- self._port, self._net_uuid, 'vxlan',
- None, None, self._fixed_ips,
- n_const.DEVICE_OWNER_DVR_INTERFACE,
- False)
- self.agent.port_bound(self._compute_port,
- self._net_uuid, 'vxlan',
- None, None,
- self._compute_fixed_ips,
- device_owner, False)
- self.assertTrue(add_flow_tun_fn.called)
- self.assertTrue(add_flow_int_fn.called)
-
+ mock.patch.object(
+ self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
+ return_value={'gateway_ip': gateway_ip,
+ 'cidr': cidr,
+ 'ip_version': ip_version,
+ 'gateway_mac': gateway_mac}),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_ports_on_host_by_subnet',
+ return_value=[]),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'get_vif_port_by_id',
+ return_value=self._port),
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),
+ ) as (get_subnet_fn, get_cphost_fn, get_vif_fn, _, _, _, _):
+ self.agent.port_bound(
+ self._port, self._net_uuid, 'vxlan',
+ None, None, self._fixed_ips,
+ n_const.DEVICE_OWNER_DVR_INTERFACE,
+ False)
+ lvid = self.agent.local_vlan_map[self._net_uuid].vlan
+ self.assertEqual(
+ self._expected_port_bound(self._port, lvid),
+ int_br.mock_calls)
+ expected_on_tun_br = [
+ mock.call.provision_local_vlan(
+ network_type='vxlan',
+ segmentation_id=None,
+ lvid=lvid,
+ distributed=True),
+ ] + self._expected_install_dvr_process(
+ port=self._port,
+ lvid=lvid,
+ ip_version=ip_version,
+ gateway_ip=gateway_ip,
+ gateway_mac=gateway_mac)
+ self.assertEqual(expected_on_tun_br, tun_br.mock_calls)
+ int_br.reset_mock()
+ tun_br.reset_mock()
+ self.agent.port_bound(self._compute_port,
+ self._net_uuid, 'vxlan',
+ None, None,
+ self._compute_fixed_ips,
+ device_owner, False)
+ self.assertEqual(
+ [
+ mock.call.install_dvr_to_src_mac(
+ network_type='vxlan',
+ gateway_mac='aa:bb:cc:11:22:33',
+ dst_mac=self._compute_port.vif_mac,
+ dst_port=self._compute_port.ofport,
+ vlan_tag=lvid,
+ ),
+ ] + self._expected_port_bound(self._compute_port, lvid),
+ int_br.mock_calls)
+ self.assertEqual([], tun_br.mock_calls)
+
+ int_br.reset_mock()
+ tun_br.reset_mock()
with contextlib.nested(
mock.patch.object(self.agent, 'reclaim_local_vlan'),
mock.patch.object(self.agent.plugin_rpc, 'update_device_down',
return_value=None),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'delete_flows')) as (reclaim_vlan_fn,
- update_dev_down_fn,
- delete_flows_int_fn):
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),
+ ) as (reclaim_vlan_fn, update_dev_down_fn, _, _, _, _):
self.agent.treat_devices_removed([self._compute_port.vif_id])
- expected = [
- mock.call(
- table=constants.DVR_TO_SRC_MAC,
- dl_dst=self._compute_port.vif_mac,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan))]
- self.assertEqual(expected, delete_flows_int_fn.call_args_list)
+ int_br.assert_has_calls([
+ mock.call.delete_dvr_to_src_mac(
+ network_type='vxlan',
+ vlan_tag=lvid,
+ dst_mac=self._compute_port.vif_mac,
+ ),
+ ])
+ self.assertEqual([], tun_br.mock_calls)
def test_treat_devices_removed_for_dvr_with_compute_ports(self):
self._test_treat_devices_removed_for_dvr(
def test_treat_devices_removed_for_dvr_csnat_port(self, ofport=10):
self._setup_for_dvr_test()
+ gateway_mac = 'aa:bb:cc:11:22:33'
+ int_br = mock.create_autospec(self.agent.int_br)
+ tun_br = mock.create_autospec(self.agent.tun_br)
+ int_br.set_db_attribute.return_value = True
+ int_br.db_get_val.return_value = {}
with contextlib.nested(
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'set_db_attribute',
- return_value=True),
- mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
- 'db_get_val',
- return_value={})):
- with contextlib.nested(
- mock.patch.object(
- self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
- return_value={'gateway_ip': '1.1.1.1',
- 'cidr': '1.1.1.0/24',
- 'ip_version': 4,
- 'gateway_mac': 'aa:bb:cc:11:22:33'}),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_ports_on_host_by_subnet',
- return_value=[]),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'get_vif_port_by_id',
- return_value=self._port),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
- ) as (get_subnet_fn, get_cphost_fn,
- get_vif_fn, add_flow_int_fn,
- add_flow_tun_fn, delete_flows_tun_fn):
- self.agent.port_bound(
- self._port, self._net_uuid, 'vxlan',
- None, None, self._fixed_ips,
- n_const.DEVICE_OWNER_ROUTER_SNAT,
- False)
- self.assertTrue(add_flow_int_fn.called)
+ mock.patch.object(
+ self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
+ return_value={'gateway_ip': '1.1.1.1',
+ 'cidr': '1.1.1.0/24',
+ 'ip_version': 4,
+ 'gateway_mac': gateway_mac}),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_ports_on_host_by_subnet',
+ return_value=[]),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'get_vif_port_by_id',
+ return_value=self._port),
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),
+ ) as (get_subnet_fn, get_cphost_fn, get_vif_fn, _, _, _, _):
+ self.agent.port_bound(
+ self._port, self._net_uuid, 'vxlan',
+ None, None, self._fixed_ips,
+ n_const.DEVICE_OWNER_ROUTER_SNAT,
+ False)
+ lvid = self.agent.local_vlan_map[self._net_uuid].vlan
+ expected_on_int_br = [
+ mock.call.install_dvr_to_src_mac(
+ network_type='vxlan',
+ gateway_mac=gateway_mac,
+ dst_mac=self._port.vif_mac,
+ dst_port=self._port.ofport,
+ vlan_tag=lvid,
+ ),
+ ] + self._expected_port_bound(self._port, lvid)
+ self.assertEqual(expected_on_int_br, int_br.mock_calls)
+ expected_on_tun_br = [
+ mock.call.provision_local_vlan(
+ network_type='vxlan',
+ lvid=lvid,
+ segmentation_id=None,
+ distributed=True,
+ ),
+ ]
+ self.assertEqual(expected_on_tun_br, tun_br.mock_calls)
+ int_br.reset_mock()
+ tun_br.reset_mock()
with contextlib.nested(
mock.patch.object(self.agent, 'reclaim_local_vlan'),
mock.patch.object(self.agent.plugin_rpc, 'update_device_down',
return_value=None),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'delete_flows')) as (reclaim_vlan_fn,
- update_dev_down_fn,
- delete_flows_int_fn):
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),
+ ) as (reclaim_vlan_fn, update_dev_down_fn, _, _, _, _):
self.agent.treat_devices_removed([self._port.vif_id])
- self.assertTrue(delete_flows_int_fn.called)
+ expected_on_int_br = [
+ mock.call.delete_dvr_to_src_mac(
+ network_type='vxlan',
+ dst_mac=self._port.vif_mac,
+ vlan_tag=lvid,
+ ),
+ ]
+ self.assertEqual(expected_on_int_br, int_br.mock_calls)
+ expected_on_tun_br = []
+ self.assertEqual(expected_on_tun_br, tun_br.mock_calls)
def test_setup_dvr_flows_on_int_br(self):
self._setup_for_dvr_test()
+ int_br = mock.create_autospec(self.agent.int_br)
+ tun_br = mock.create_autospec(self.agent.tun_br)
with contextlib.nested(
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'remove_all_flows'),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(
- self.agent.dvr_agent.plugin_rpc,
- 'get_dvr_mac_address_list',
- return_value=[{'host': 'cn1',
- 'mac_address': 'aa:bb:cc:dd:ee:ff'},
- {'host': 'cn2',
- 'mac_address': '11:22:33:44:55:66'}])) as \
- (remove_flows_fn, add_int_flow_fn, add_tun_flow_fn,
- get_mac_list_fn):
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),
+ mock.patch.object(
+ self.agent.dvr_agent.plugin_rpc,
+ 'get_dvr_mac_address_list',
+ return_value=[{'host': 'cn1',
+ 'mac_address': 'aa:bb:cc:dd:ee:ff'},
+ {'host': 'cn2',
+ 'mac_address': '11:22:33:44:55:66'}])
+ ) as (_, _, _, _, get_mac_list_fn):
self.agent.dvr_agent.setup_dvr_flows_on_integ_br()
self.assertTrue(self.agent.dvr_agent.in_distributed_mode())
physical_networks = self.agent.dvr_agent.bridge_mappings.keys()
ioport = self.agent.dvr_agent.int_ofports[physical_networks[0]]
- expected = [
- mock.call(table=constants.CANARY_TABLE,
- priority=0,
- actions="drop"),
- mock.call(table=constants.DVR_TO_SRC_MAC,
- priority=1,
- actions="drop"),
- mock.call(table=constants.DVR_TO_SRC_MAC_VLAN,
- priority=1,
- actions="drop"),
- mock.call(table=constants.LOCAL_SWITCHING,
- priority=1,
- actions="normal"),
- mock.call(
- table=constants.LOCAL_SWITCHING, priority=2,
- actions="drop",
- in_port=ioport)]
- self.assertTrue(remove_flows_fn.called)
- self.assertEqual(expected, add_int_flow_fn.call_args_list)
- self.assertEqual(add_int_flow_fn.call_count, 5)
+ expected_on_int_br = [
+ # setup_dvr_flows_on_integ_br
+ mock.call.delete_flows(),
+ mock.call.setup_canary_table(),
+ mock.call.install_drop(table_id=constants.DVR_TO_SRC_MAC,
+ priority=1),
+ mock.call.install_drop(table_id=constants.DVR_TO_SRC_MAC_VLAN,
+ priority=1),
+ mock.call.install_normal(table_id=constants.LOCAL_SWITCHING,
+ priority=1),
+ mock.call.install_drop(table_id=constants.LOCAL_SWITCHING,
+ priority=2,
+ in_port=ioport),
+ ]
+ self.assertEqual(expected_on_int_br, int_br.mock_calls)
+ self.assertEqual([], tun_br.mock_calls)
def test_get_dvr_mac_address(self):
self._setup_for_dvr_test()
def test_get_dvr_mac_address_exception(self):
self._setup_for_dvr_test()
self.agent.dvr_agent.dvr_mac_address = None
+ int_br = mock.create_autospec(self.agent.int_br)
with contextlib.nested(
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
'get_dvr_mac_address_by_host',
side_effect=oslo_messaging.RemoteError),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'add_flow')) as (gd_mac, add_int_flow_fn):
-
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ ) as (gd_mac, _, _):
self.agent.dvr_agent.get_dvr_mac_address()
self.assertIsNone(self.agent.dvr_agent.dvr_mac_address)
self.assertFalse(self.agent.dvr_agent.in_distributed_mode())
- self.assertEqual(add_int_flow_fn.call_count, 1)
+ self.assertEqual([mock.call.install_normal()], int_br.mock_calls)
def test_get_dvr_mac_address_retried(self):
valid_entry = {'host': 'cn1', 'mac_address': 'aa:22:33:44:55:66'}
# Raise a timeout every time until we give up, currently 5 tries
self._setup_for_dvr_test()
self.agent.dvr_agent.dvr_mac_address = None
+ int_br = mock.create_autospec(self.agent.int_br)
with contextlib.nested(
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_dvr_mac_address_by_host',
- side_effect=raise_timeout),
- mock.patch.object(utils, "execute"),
- ) as (rpc_mock, execute_mock):
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_dvr_mac_address_by_host',
+ side_effect=raise_timeout),
+ mock.patch.object(utils, "execute"),
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ ) as (rpc_mock, execute_mock, _, _):
self.agent.dvr_agent.get_dvr_mac_address()
self.assertIsNone(self.agent.dvr_agent.dvr_mac_address)
self.assertFalse(self.agent.dvr_agent.in_distributed_mode())
self._setup_for_dvr_test()
newhost = 'cn2'
newmac = 'aa:bb:cc:dd:ee:ff'
- int_ofport = self.agent.dvr_agent.int_ofports['physeth1']
- patch_int_ofport = self.agent.dvr_agent.patch_int_ofport
- patch_tun_ofport = self.agent.dvr_agent.patch_tun_ofport
+ int_br = mock.create_autospec(self.agent.int_br)
+ tun_br = mock.create_autospec(self.agent.tun_br)
+ phys_br = mock.create_autospec(self.br_phys_cls('br-phys'))
+ physical_network = 'physeth1'
with contextlib.nested(
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
- mock.patch.object(self.agent.dvr_agent.phys_brs['physeth1'],
- 'add_flow')
- ) as (add_flow_fn, add_flow_tn_fn, del_flows_fn, add_flow_phys_fn):
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
+ mock.patch.dict(self.agent.phys_brs,
+ {physical_network: phys_br}),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),
+ mock.patch.dict(self.agent.dvr_agent.phys_brs,
+ {physical_network: phys_br}),
+ ):
self.agent.dvr_agent.\
dvr_mac_address_update(
dvr_macs=[{'host': newhost,
'mac_address': newmac}])
- expected = [
- mock.call(table=constants.LOCAL_SWITCHING,
- priority=4,
- in_port=int_ofport,
- dl_src=newmac,
- actions="resubmit(,%s)" %
- constants.DVR_TO_SRC_MAC_VLAN),
- mock.call(table=constants.LOCAL_SWITCHING,
- priority=2,
- in_port=patch_tun_ofport,
- dl_src=newmac,
- actions="resubmit(,%s)" %
- constants.DVR_TO_SRC_MAC)]
- self.assertEqual(expected, add_flow_fn.call_args_list)
- add_flow_phys_fn.assert_called_with(
- table=constants.DVR_NOT_LEARN_VLAN,
- priority=2,
- dl_src=newmac,
- actions="output:%s" %
- self.agent.dvr_agent.phys_ofports['physeth1'])
- add_flow_tn_fn.assert_called_with(table=constants.DVR_NOT_LEARN,
- priority=1,
- dl_src=newmac,
- actions="output:%s"
- % patch_int_ofport)
- self.assertFalse(del_flows_fn.called)
+ expected_on_int_br = [
+ mock.call.add_dvr_mac_vlan(
+ mac=newmac,
+ port=self.agent.int_ofports[physical_network]),
+ mock.call.add_dvr_mac_tun(
+ mac=newmac,
+ port=self.agent.patch_tun_ofport),
+ ]
+ expected_on_tun_br = [
+ mock.call.add_dvr_mac_tun(
+ mac=newmac,
+ port=self.agent.patch_int_ofport),
+ ]
+ expected_on_phys_br = [
+ mock.call.add_dvr_mac_vlan(
+ mac=newmac,
+ port=self.agent.phys_ofports[physical_network]),
+ ]
+ self.assertEqual(expected_on_int_br, int_br.mock_calls)
+ self.assertEqual(expected_on_tun_br, tun_br.mock_calls)
+ self.assertEqual(expected_on_phys_br, phys_br.mock_calls)
+ int_br.reset_mock()
+ tun_br.reset_mock()
+ phys_br.reset_mock()
with contextlib.nested(
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows'),
- mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
- mock.patch.object(self.agent.dvr_agent.phys_brs['physeth1'],
- 'delete_flows'),
- ) as (add_flow_fn, del_flows_tn_fn, del_flows_fn, del_flows_phys_fn):
+ mock.patch.object(self.agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
+ mock.patch.dict(self.agent.phys_brs,
+ {physical_network: phys_br}),
+ mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),
+ mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),
+ mock.patch.dict(self.agent.dvr_agent.phys_brs,
+ {physical_network: phys_br}),
+ ):
self.agent.dvr_agent.dvr_mac_address_update(dvr_macs=[])
- ioport = self.agent.dvr_agent.int_ofports['physeth1']
- expected = [
- mock.call(table=constants.LOCAL_SWITCHING,
- in_port=ioport,
- dl_src=newmac),
- mock.call(table=constants.LOCAL_SWITCHING,
- in_port=patch_tun_ofport,
- dl_src=newmac)]
- self.assertEqual(expected, del_flows_fn.call_args_list)
- del_flows_phys_fn.asert_called_with(
- table=constants.DVR_NOT_LEARN_VLAN,
- dl_src=newmac)
- del_flows_tn_fn.assert_called_with(table=constants.DVR_NOT_LEARN,
- dl_src=newmac)
- self.assertFalse(add_flow_fn.called)
+ expected_on_int_br = [
+ mock.call.remove_dvr_mac_vlan(
+ mac=newmac),
+ mock.call.remove_dvr_mac_tun(
+ mac=newmac,
+ port=self.agent.patch_tun_ofport),
+ ]
+ expected_on_tun_br = [
+ mock.call.remove_dvr_mac_tun(
+ mac=newmac),
+ ]
+ expected_on_phys_br = [
+ mock.call.remove_dvr_mac_vlan(
+ mac=newmac),
+ ]
+ self.assertEqual(expected_on_int_br, int_br.mock_calls)
+ self.assertEqual(expected_on_tun_br, tun_br.mock_calls)
+ self.assertEqual(expected_on_phys_br, phys_br.mock_calls)
def test_ovs_restart(self):
self._setup_for_dvr_test()
'setup_dvr_flows_on_phys_br', 'setup_dvr_mac_flows_on_all_brs')
reset_mocks = [mock.patch.object(self.agent.dvr_agent, method).start()
for method in reset_methods]
+ tun_br = mock.create_autospec(self.agent.tun_br)
with contextlib.nested(
mock.patch.object(self.agent, 'check_ovs_status',
return_value=constants.OVS_RESTARTED),
mock.patch.object(self.agent, '_agent_has_updates',
- side_effect=TypeError('loop exit'))
+ side_effect=TypeError('loop exit')),
+ mock.patch.object(self.agent, 'tun_br', new=tun_br),
):
# block RPC calls and bridge calls
self.agent.setup_physical_bridges = mock.Mock()
except TypeError:
pass
self.assertTrue(all([x.called for x in reset_mocks]))
+
+
+class TestOvsDvrNeutronAgentOFCtl(TestOvsDvrNeutronAgent,
+ ovs_test_base.OVSOFCtlTestBase):
+ pass
from neutron.agent.common import ovs_lib
from neutron.agent.linux import ip_lib
from neutron.plugins.common import constants as p_const
-from neutron.plugins.openvswitch.agent import ovs_neutron_agent
from neutron.plugins.openvswitch.common import constants
-from neutron.tests import base
+from neutron.tests.unit.plugins.openvswitch.agent import ovs_test_base
# Useful global dummy variables.
VIF_PORT = ovs_lib.VifPort('port', OFPORT_NUM,
VIF_ID, VIF_MAC, 'switch')
VIF_PORTS = {VIF_ID: VIF_PORT}
-LVM = ovs_neutron_agent.LocalVLANMapping(LV_ID, 'gre', None, LS_ID, VIF_PORTS)
-LVM_FLAT = ovs_neutron_agent.LocalVLANMapping(
- LV_ID, 'flat', 'net1', LS_ID, VIF_PORTS)
-LVM_VLAN = ovs_neutron_agent.LocalVLANMapping(
- LV_ID, 'vlan', 'net1', LS_ID, VIF_PORTS)
FIXED_IPS = [{'subnet_id': 'my-subnet-uuid',
'ip_address': '1.1.1.1'}]
VM_DEVICE_OWNER = "compute:None"
self.vlan_id = vlan_id
-class TunnelTest(base.BaseTestCase):
+class TunnelTest(object):
USE_VETH_INTERCONNECTION = False
VETH_MTU = None
self.MAP_TUN_INT_OFPORT = 33333
self.MAP_TUN_PHY_OFPORT = 44444
+ self.LVM = self.mod_agent.LocalVLANMapping(
+ LV_ID, 'gre', None, LS_ID, VIF_PORTS)
+ self.LVM_FLAT = self.mod_agent.LocalVLANMapping(
+ LV_ID, 'flat', 'net1', LS_ID, VIF_PORTS)
+ self.LVM_VLAN = self.mod_agent.LocalVLANMapping(
+ LV_ID, 'vlan', 'net1', LS_ID, VIF_PORTS)
+
self.inta = mock.Mock()
self.intb = mock.Mock()
- self.ovs_bridges = {self.INT_BRIDGE: mock.Mock(),
- self.TUN_BRIDGE: mock.Mock(),
- self.MAP_TUN_BRIDGE: mock.Mock(),
- }
+ self.ovs_bridges = {
+ self.INT_BRIDGE: mock.create_autospec(
+ self.br_int_cls('br-int')),
+ self.TUN_BRIDGE: mock.create_autospec(
+ self.br_tun_cls('br-tun')),
+ self.MAP_TUN_BRIDGE: mock.create_autospec(
+ self.br_phys_cls('br-phys')),
+ }
self.ovs_int_ofports = {
'patch-tun': self.TUN_OFPORT,
'int-%s' % self.MAP_TUN_BRIDGE: self.MAP_TUN_INT_OFPORT
}
- self.mock_bridge = mock.patch.object(ovs_lib, 'OVSBridge').start()
- self.mock_bridge.side_effect = (lambda br_name:
- self.ovs_bridges[br_name])
+ def lookup_br(br_name, *args, **kwargs):
+ return self.ovs_bridges[br_name]
+
+ self.mock_int_bridge_cls = mock.patch(self._BR_INT_CLASS,
+ autospec=True).start()
+ self.mock_int_bridge_cls.side_effect = lookup_br
+ self.mock_phys_bridge_cls = mock.patch(self._BR_PHYS_CLASS,
+ autospec=True).start()
+ self.mock_phys_bridge_cls.side_effect = lookup_br
+ self.mock_tun_bridge_cls = mock.patch(self._BR_TUN_CLASS,
+ autospec=True).start()
+ self.mock_tun_bridge_cls.side_effect = lookup_br
self.mock_int_bridge = self.ovs_bridges[self.INT_BRIDGE]
self.mock_int_bridge.add_port.return_value = self.MAP_TUN_INT_OFPORT
self._define_expected_calls()
- def _define_expected_calls(self):
- self.mock_bridge_expected = [
+ def _define_expected_calls(self, arp_responder=False):
+ self.mock_int_bridge_cls_expected = [
mock.call(self.INT_BRIDGE),
+ ]
+ self.mock_phys_bridge_cls_expected = [
mock.call(self.MAP_TUN_BRIDGE),
+ ]
+ self.mock_tun_bridge_cls_expected = [
mock.call(self.TUN_BRIDGE),
]
self.mock_int_bridge_expected = [
mock.call.create(),
mock.call.set_secure_mode(),
+ mock.call.setup_controllers(mock.ANY),
mock.call.delete_port('patch-tun'),
- mock.call.remove_all_flows(),
- mock.call.add_flow(priority=1, actions='normal'),
- mock.call.add_flow(priority=0, table=constants.CANARY_TABLE,
- actions='drop'),
+ mock.call.setup_default_table(),
]
self.mock_map_tun_bridge_expected = [
- mock.call.remove_all_flows(),
- mock.call.add_flow(priority=1, actions='normal'),
+ mock.call.setup_controllers(mock.ANY),
+ mock.call.setup_default_table(),
mock.call.delete_port('phy-%s' % self.MAP_TUN_BRIDGE),
mock.call.add_patch_port('phy-%s' % self.MAP_TUN_BRIDGE,
- constants.NONEXISTENT_PEER),
- ]
+ constants.NONEXISTENT_PEER), ]
self.mock_int_bridge_expected += [
mock.call.delete_port('int-%s' % self.MAP_TUN_BRIDGE),
mock.call.add_patch_port('int-%s' % self.MAP_TUN_BRIDGE,
]
self.mock_int_bridge_expected += [
- mock.call.add_flow(priority=2,
- in_port=self.MAP_TUN_INT_OFPORT,
- actions='drop'),
+ mock.call.drop_port(in_port=self.MAP_TUN_INT_OFPORT),
mock.call.set_db_attribute(
'Interface', 'int-%s' % self.MAP_TUN_BRIDGE,
'options:peer', 'phy-%s' % self.MAP_TUN_BRIDGE),
]
self.mock_map_tun_bridge_expected += [
- mock.call.add_flow(priority=2,
- in_port=self.MAP_TUN_PHY_OFPORT,
- actions='drop'),
+ mock.call.drop_port(in_port=self.MAP_TUN_PHY_OFPORT),
mock.call.set_db_attribute(
'Interface', 'phy-%s' % self.MAP_TUN_BRIDGE,
'options:peer', 'int-%s' % self.MAP_TUN_BRIDGE),
self.mock_tun_bridge_expected = [
mock.call.reset_bridge(secure_mode=True),
+ mock.call.setup_controllers(mock.ANY),
mock.call.add_patch_port('patch-int', 'patch-tun'),
]
self.mock_int_bridge_expected += [
]
self.mock_tun_bridge_expected += [
- mock.call.remove_all_flows(),
- mock.call.add_flow(priority=1,
- actions="resubmit(,%s)" %
- constants.PATCH_LV_TO_TUN,
- in_port=self.INT_OFPORT),
- mock.call.add_flow(priority=0, actions="drop"),
- mock.call.add_flow(priority=0, table=constants.PATCH_LV_TO_TUN,
- dl_dst=UCAST_MAC,
- actions="resubmit(,%s)" %
- constants.UCAST_TO_TUN),
- mock.call.add_flow(priority=0, table=constants.PATCH_LV_TO_TUN,
- dl_dst=BCAST_MAC,
- actions="resubmit(,%s)" %
- constants.FLOOD_TO_TUN),
- ]
- for tunnel_type in constants.TUNNEL_NETWORK_TYPES:
- self.mock_tun_bridge_expected.append(
- mock.call.add_flow(
- table=constants.TUN_TABLE[tunnel_type],
- priority=0,
- actions="drop"))
- learned_flow = ("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[]" %
- constants.UCAST_TO_TUN)
- self.mock_tun_bridge_expected += [
- mock.call.add_flow(table=constants.LEARN_FROM_TUN,
- priority=1,
- actions="learn(%s),output:%s" %
- (learned_flow, self.INT_OFPORT)),
- mock.call.add_flow(table=constants.UCAST_TO_TUN,
- priority=0,
- actions="resubmit(,%s)" %
- constants.FLOOD_TO_TUN),
- mock.call.add_flow(table=constants.FLOOD_TO_TUN,
- priority=0,
- actions="drop")
+ mock.call.delete_flows(),
+ mock.call.setup_default_table(self.INT_OFPORT, arp_responder),
]
self.device_exists_expected = []
self.execute_expected = []
def _build_agent(self, **kwargs):
+ bridge_classes = {
+ 'br_int': self.mock_int_bridge_cls,
+ 'br_phys': self.mock_phys_bridge_cls,
+ 'br_tun': self.mock_tun_bridge_cls,
+ }
+ kwargs.setdefault('bridge_classes', bridge_classes)
kwargs.setdefault('integ_br', self.INT_BRIDGE)
kwargs.setdefault('tun_br', self.TUN_BRIDGE)
kwargs.setdefault('local_ip', '10.0.0.1')
kwargs.setdefault('veth_mtu', self.VETH_MTU)
kwargs.setdefault('use_veth_interconnection',
self.USE_VETH_INTERCONNECTION)
- return ovs_neutron_agent.OVSNeutronAgent(**kwargs)
+ return self.mod_agent.OVSNeutronAgent(**kwargs)
def _verify_mock_call(self, mock_obj, expected):
mock_obj.assert_has_calls(expected)
self.assertEqual(len(mock_obj.mock_calls), len(expected))
def _verify_mock_calls(self):
- self._verify_mock_call(self.mock_bridge, self.mock_bridge_expected)
+ self._verify_mock_call(self.mock_int_bridge_cls,
+ self.mock_int_bridge_cls_expected)
+ self._verify_mock_call(self.mock_tun_bridge_cls,
+ self.mock_tun_bridge_cls_expected)
+ self._verify_mock_call(self.mock_phys_bridge_cls,
+ self.mock_phys_bridge_cls_expected)
self._verify_mock_call(self.mock_int_bridge,
self.mock_int_bridge_expected)
self._verify_mock_call(self.mock_map_tun_bridge,
# The next two tests use l2_pop flag to test ARP responder
def test_construct_with_arp_responder(self):
self._build_agent(l2_population=True, arp_responder=True)
- self.mock_tun_bridge_expected.insert(
- 5, mock.call.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)
- )
- self.mock_tun_bridge_expected.insert(
- 12, mock.call.add_flow(table=constants.ARP_RESPONDER,
- priority=0,
- actions="resubmit(,%s)" %
- constants.FLOOD_TO_TUN)
- )
+ self._define_expected_calls(True)
self._verify_mock_calls()
def test_construct_without_arp_responder(self):
self._verify_mock_calls()
def test_provision_local_vlan(self):
- ofports = ','.join(TUN_OFPORTS[p_const.TYPE_GRE].values())
+ ofports = TUN_OFPORTS[p_const.TYPE_GRE].values()
self.mock_tun_bridge_expected += [
- mock.call.mod_flow(table=constants.FLOOD_TO_TUN,
- dl_vlan=LV_ID,
- actions="strip_vlan,"
- "set_tunnel:%s,output:%s" %
- (LS_ID, ofports)),
- mock.call.add_flow(table=constants.TUN_TABLE['gre'],
- priority=1,
- tun_id=LS_ID,
- actions="mod_vlan_vid:%s,resubmit(,%s)" %
- (LV_ID, constants.LEARN_FROM_TUN)),
+ mock.call.install_flood_to_tun(LV_ID, LS_ID, ofports),
+ mock.call.provision_local_vlan(
+ network_type=p_const.TYPE_GRE,
+ lvid=LV_ID,
+ segmentation_id=LS_ID),
]
a = self._build_agent()
self._verify_mock_calls()
def test_provision_local_vlan_flat(self):
- action_string = 'strip_vlan,normal'
self.mock_map_tun_bridge_expected.append(
- mock.call.add_flow(priority=4, in_port=self.MAP_TUN_PHY_OFPORT,
- dl_vlan=LV_ID, actions=action_string))
-
- action_string = 'mod_vlan_vid:%s,normal' % LV_ID
+ mock.call.provision_local_vlan(
+ port=self.MAP_TUN_PHY_OFPORT,
+ lvid=LV_ID,
+ segmentation_id=None,
+ distributed=False))
self.mock_int_bridge_expected.append(
- mock.call.add_flow(priority=3, in_port=self.INT_OFPORT,
- dl_vlan=65535, actions=action_string))
+ mock.call.provision_local_vlan(
+ port=self.INT_OFPORT,
+ lvid=LV_ID,
+ segmentation_id=None))
a = self._build_agent()
a.available_local_vlans = set([LV_ID])
self._verify_mock_calls()
def test_provision_local_vlan_vlan(self):
- action_string = 'mod_vlan_vid:%s,normal' % LS_ID
self.mock_map_tun_bridge_expected.append(
- mock.call.add_flow(priority=4, in_port=self.MAP_TUN_PHY_OFPORT,
- dl_vlan=LV_ID, actions=action_string))
-
- action_string = 'mod_vlan_vid:%s,normal' % LV_ID
+ mock.call.provision_local_vlan(
+ port=self.MAP_TUN_PHY_OFPORT,
+ lvid=LV_ID,
+ segmentation_id=LS_ID,
+ distributed=False))
self.mock_int_bridge_expected.append(
- mock.call.add_flow(priority=3, in_port=self.INT_OFPORT,
- dl_vlan=LS_ID, actions=action_string))
-
+ mock.call.provision_local_vlan(
+ port=self.INT_OFPORT,
+ lvid=LV_ID,
+ segmentation_id=LS_ID))
a = self._build_agent()
a.available_local_vlans = set([LV_ID])
a.phys_brs['net1'] = self.mock_map_tun_bridge
def test_reclaim_local_vlan(self):
self.mock_tun_bridge_expected += [
- mock.call.delete_flows(
- table=constants.TUN_TABLE['gre'], tun_id=LS_ID),
- mock.call.delete_flows(dl_vlan=LVM.vlan)
+ mock.call.reclaim_local_vlan(network_type='gre',
+ segmentation_id=LS_ID),
+ mock.call.delete_flood_to_tun(LV_ID),
+ mock.call.delete_unicast_to_tun(LV_ID, None),
+ mock.call.delete_arp_responder(LV_ID, None),
]
a = self._build_agent()
a.available_local_vlans = set()
- a.local_vlan_map[NET_UUID] = LVM
+ a.local_vlan_map[NET_UUID] = self.LVM
a.reclaim_local_vlan(NET_UUID)
- self.assertIn(LVM.vlan, a.available_local_vlans)
+ self.assertIn(self.LVM.vlan, a.available_local_vlans)
self._verify_mock_calls()
def test_reclaim_local_vlan_flat(self):
self.mock_map_tun_bridge_expected.append(
- mock.call.delete_flows(
- in_port=self.MAP_TUN_PHY_OFPORT, dl_vlan=LVM_FLAT.vlan))
+ mock.call.reclaim_local_vlan(
+ port=self.MAP_TUN_PHY_OFPORT,
+ lvid=self.LVM_FLAT.vlan))
self.mock_int_bridge_expected.append(
- mock.call.delete_flows(
- dl_vlan=65535, in_port=self.INT_OFPORT))
-
+ mock.call.reclaim_local_vlan(
+ port=self.INT_OFPORT,
+ segmentation_id=None))
a = self._build_agent()
a.phys_brs['net1'] = self.mock_map_tun_bridge
a.phys_ofports['net1'] = self.MAP_TUN_PHY_OFPORT
a.int_ofports['net1'] = self.INT_OFPORT
a.available_local_vlans = set()
- a.local_vlan_map[NET_UUID] = LVM_FLAT
+ a.local_vlan_map[NET_UUID] = self.LVM_FLAT
a.reclaim_local_vlan(NET_UUID)
- self.assertIn(LVM_FLAT.vlan, a.available_local_vlans)
+ self.assertIn(self.LVM_FLAT.vlan, a.available_local_vlans)
self._verify_mock_calls()
def test_reclaim_local_vlan_vlan(self):
self.mock_map_tun_bridge_expected.append(
- mock.call.delete_flows(
- in_port=self.MAP_TUN_PHY_OFPORT, dl_vlan=LVM_VLAN.vlan))
+ mock.call.reclaim_local_vlan(
+ port=self.MAP_TUN_PHY_OFPORT,
+ lvid=self.LVM_VLAN.vlan))
self.mock_int_bridge_expected.append(
- mock.call.delete_flows(
- dl_vlan=LS_ID, in_port=self.INT_OFPORT))
-
+ mock.call.reclaim_local_vlan(
+ port=self.INT_OFPORT,
+ segmentation_id=LS_ID))
a = self._build_agent()
a.phys_brs['net1'] = self.mock_map_tun_bridge
a.phys_ofports['net1'] = self.MAP_TUN_PHY_OFPORT
a.int_ofports['net1'] = self.INT_OFPORT
a.available_local_vlans = set()
- a.local_vlan_map[NET_UUID] = LVM_VLAN
+ a.local_vlan_map[NET_UUID] = self.LVM_VLAN
a.reclaim_local_vlan(NET_UUID)
- self.assertIn(LVM_VLAN.vlan, a.available_local_vlans)
+ self.assertIn(self.LVM_VLAN.vlan, a.available_local_vlans)
self._verify_mock_calls()
def test_port_bound(self):
vlan_mapping)]
a = self._build_agent()
- a.local_vlan_map[NET_UUID] = LVM
+ a.local_vlan_map[NET_UUID] = self.LVM
a.local_dvr_map = {}
+ self.ovs_bridges[self.INT_BRIDGE].db_get_val.return_value = {}
a.port_bound(VIF_PORT, NET_UUID, 'gre', None, LS_ID,
FIXED_IPS, VM_DEVICE_OWNER, False)
self._verify_mock_calls()
def test_port_unbound(self):
- with mock.patch.object(ovs_neutron_agent.OVSNeutronAgent,
+ with mock.patch.object(self.mod_agent.OVSNeutronAgent,
'reclaim_local_vlan') as reclaim_local_vlan:
a = self._build_agent()
- a.local_vlan_map[NET_UUID] = LVM
+ a.local_vlan_map[NET_UUID] = self.LVM
a.port_unbound(VIF_ID, NET_UUID)
reclaim_local_vlan.assert_called_once_with(NET_UUID)
mock.call.db_get_val('Port', VIF_PORT.port_name, 'tag'),
mock.call.set_db_attribute(
'Port', VIF_PORT.port_name,
- 'tag', ovs_neutron_agent.DEAD_VLAN_TAG),
- mock.call.add_flow(priority=2, in_port=VIF_PORT.ofport,
- actions='drop')
+ 'tag', self.mod_agent.DEAD_VLAN_TAG),
+ mock.call.drop_port(in_port=VIF_PORT.ofport),
]
a = self._build_agent()
a.available_local_vlans = set([LV_ID])
- a.local_vlan_map[NET_UUID] = LVM
+ a.local_vlan_map[NET_UUID] = self.LVM
+ self.ovs_bridges[self.INT_BRIDGE].db_get_val.return_value = mock.Mock()
a.port_dead(VIF_PORT)
self._verify_mock_calls()
self.mock_tun_bridge_expected += [
mock.call.add_tunnel_port('gre-0a000a01', '10.0.10.1', '10.0.0.1',
'gre', 4789, True),
- mock.call.add_flow(priority=1, in_port=tunnel_port,
- actions='resubmit(,3)')
+ mock.call.setup_tunnel_port('gre', tunnel_port),
]
a = self._build_agent()
'removed': set(['tap0'])}
self.mock_int_bridge_expected += [
- mock.call.dump_flows_for_table(constants.CANARY_TABLE),
- mock.call.dump_flows_for_table(constants.CANARY_TABLE)
+ mock.call.check_canary_table(),
+ mock.call.check_canary_table()
]
+ self.ovs_bridges[self.INT_BRIDGE].check_canary_table.return_value = \
+ constants.OVS_NORMAL
with contextlib.nested(
mock.patch.object(log.KeywordArgumentAdapter, 'exception'),
- mock.patch.object(ovs_neutron_agent.OVSNeutronAgent,
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
'scan_ports'),
- mock.patch.object(ovs_neutron_agent.OVSNeutronAgent,
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
'process_network_ports'),
- mock.patch.object(ovs_neutron_agent.OVSNeutronAgent,
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
'tunnel_sync'),
mock.patch.object(time, 'sleep'),
- mock.patch.object(ovs_neutron_agent.OVSNeutronAgent,
+ mock.patch.object(self.mod_agent.OVSNeutronAgent,
'update_stale_ofport_rules')
) as (log_exception, scan_ports, process_network_ports,
ts, time_sleep, update_stale):
self._verify_mock_calls()
+class TunnelTestOFCtl(TunnelTest, ovs_test_base.OVSOFCtlTestBase):
+ pass
+
+
class TunnelTestUseVethInterco(TunnelTest):
USE_VETH_INTERCONNECTION = True
- def _define_expected_calls(self):
- self.mock_bridge_expected = [
+ def _define_expected_calls(self, arp_responder=False):
+ self.mock_int_bridge_cls_expected = [
mock.call(self.INT_BRIDGE),
+ ]
+ self.mock_phys_bridge_cls_expected = [
mock.call(self.MAP_TUN_BRIDGE),
+ ]
+ self.mock_tun_bridge_cls_expected = [
mock.call(self.TUN_BRIDGE),
]
self.mock_int_bridge_expected = [
mock.call.create(),
mock.call.set_secure_mode(),
+ mock.call.setup_controllers(mock.ANY),
mock.call.delete_port('patch-tun'),
- mock.call.remove_all_flows(),
- mock.call.add_flow(priority=1, actions='normal'),
- mock.call.add_flow(table=constants.CANARY_TABLE, priority=0,
- actions="drop")
+ mock.call.setup_default_table(),
]
self.mock_map_tun_bridge_expected = [
- mock.call.remove_all_flows(),
- mock.call.add_flow(priority=1, actions='normal'),
+ mock.call.setup_controllers(mock.ANY),
+ mock.call.setup_default_table(),
mock.call.delete_port('phy-%s' % self.MAP_TUN_BRIDGE),
mock.call.add_port(self.intb),
]
]
self.mock_int_bridge_expected += [
- mock.call.add_flow(priority=2,
- in_port=self.MAP_TUN_INT_OFPORT,
- actions='drop')
+ mock.call.drop_port(in_port=self.MAP_TUN_INT_OFPORT),
]
self.mock_map_tun_bridge_expected += [
- mock.call.add_flow(priority=2,
- in_port=self.MAP_TUN_PHY_OFPORT,
- actions='drop')
+ mock.call.drop_port(in_port=self.MAP_TUN_PHY_OFPORT),
]
self.mock_tun_bridge_expected = [
mock.call.reset_bridge(secure_mode=True),
+ mock.call.setup_controllers(mock.ANY),
mock.call.add_patch_port('patch-int', 'patch-tun'),
]
self.mock_int_bridge_expected += [
mock.call.get_vif_ports(),
]
self.mock_tun_bridge_expected += [
- mock.call.remove_all_flows(),
- mock.call.add_flow(priority=1,
- in_port=self.INT_OFPORT,
- actions="resubmit(,%s)" %
- constants.PATCH_LV_TO_TUN),
- mock.call.add_flow(priority=0, actions='drop'),
- mock.call.add_flow(priority=0,
- table=constants.PATCH_LV_TO_TUN,
- dl_dst=UCAST_MAC,
- actions="resubmit(,%s)" %
- constants.UCAST_TO_TUN),
- mock.call.add_flow(priority=0,
- table=constants.PATCH_LV_TO_TUN,
- dl_dst=BCAST_MAC,
- actions="resubmit(,%s)" %
- constants.FLOOD_TO_TUN),
- ]
- for tunnel_type in constants.TUNNEL_NETWORK_TYPES:
- self.mock_tun_bridge_expected.append(
- mock.call.add_flow(
- table=constants.TUN_TABLE[tunnel_type],
- priority=0,
- actions="drop"))
- learned_flow = ("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[]" %
- constants.UCAST_TO_TUN)
- self.mock_tun_bridge_expected += [
- mock.call.add_flow(table=constants.LEARN_FROM_TUN,
- priority=1,
- actions="learn(%s),output:%s" %
- (learned_flow, self.INT_OFPORT)),
- mock.call.add_flow(table=constants.UCAST_TO_TUN,
- priority=0,
- actions="resubmit(,%s)" %
- constants.FLOOD_TO_TUN),
- mock.call.add_flow(table=constants.FLOOD_TO_TUN,
- priority=0,
- actions="drop")
+ mock.call.delete_flows(),
+ mock.call.setup_default_table(self.INT_OFPORT, arp_responder),
]
self.device_exists_expected = [
'--timeout=10'])]
+class TunnelTestUseVethIntercoOFCtl(TunnelTestUseVethInterco,
+ ovs_test_base.OVSOFCtlTestBase):
+ pass
+
+
class TunnelTestWithMTU(TunnelTestUseVethInterco):
VETH_MTU = 1500
- def _define_expected_calls(self):
- super(TunnelTestWithMTU, self)._define_expected_calls()
+ def _define_expected_calls(self, arp_responder=False):
+ super(TunnelTestWithMTU, self)._define_expected_calls(arp_responder)
self.inta_expected.append(mock.call.link.set_mtu(self.VETH_MTU))
self.intb_expected.append(mock.call.link.set_mtu(self.VETH_MTU))
+
+
+class TunnelTestWithMTUOFCtl(TunnelTestWithMTU,
+ ovs_test_base.OVSOFCtlTestBase):
+ pass