# -- Notes for updating from Icehouce
+After Icehouce, most of the functionality have been folded into
+a single bridge, the integration bridge. (aka. br-int)
+The integration bridge is the only bridge which would have an
+OpenFlow connection to the embedded controller in ofagent now.
+
+- ofagent no longer uses a separate bridge for tunneling.
+ Please remove br-tun if you have one.
+
+ # ovs-vsctl del-br br-tun
+
+- ofagent no longer acts as an OpenFlow controller for physical bridges.
+ Please remove set-controller configuration from your physical bridges.
+
+ # ovs-vsctl del-controller ${PHYSICAL_BRIDGE}
+
The support of ancillary bridges has been removed after Icehouce.
While you can still use these bridges to provide connectivity,
neutron-ofagent-agent no longer reports port state changes (up/down)
from ryu.lib.packet import ethernet
from ryu.lib.packet import packet
from ryu.lib.packet import vlan
-from ryu.ofproto import ether
from neutron.openstack.common import log as logging
-from neutron.plugins.openvswitch.common import constants
+import neutron.plugins.ofagent.agent.metadata as meta
LOG = logging.getLogger(__name__)
"""
self.ryuapp = ryuapp
self._arp_tbl = {}
+ self.br = None
+
+ def set_bridge(self, br):
+ self.br = br
def _send_arp_reply(self, datapath, port, pkt):
LOG.debug("packet-out %s", pkt)
data=data)
ryu_api.send_msg(self.ryuapp, out)
- def _add_flow_to_avoid_unknown_packet(self, datapath, match):
- LOG.debug("add flow to avoid an unknown packet from packet-in")
- ofp = datapath.ofproto
- ofpp = datapath.ofproto_parser
- instructions = [ofpp.OFPInstructionGotoTable(
- table_id=constants.FLOOD_TO_TUN)]
- out = ofpp.OFPFlowMod(datapath,
- table_id=constants.PATCH_LV_TO_TUN,
- command=ofp.OFPFC_ADD,
- idle_timeout=5,
- priority=20,
- match=match,
- instructions=instructions)
- ryu_api.send_msg(self.ryuapp, out)
-
def _send_unknown_packet(self, msg, in_port, out_port):
LOG.debug("unknown packet-out in-port %(in_port)s "
"out-port %(out_port)s msg %(msg)s",
pkt.add_protocol(ethernet.ethernet(ethertype=pkt_ethernet.ethertype,
dst=pkt_ethernet.src,
src=hw_addr))
- pkt.add_protocol(vlan.vlan(cfi=pkt_vlan.cfi,
- ethertype=pkt_vlan.ethertype,
- pcp=pkt_vlan.pcp,
- vid=pkt_vlan.vid))
+ if pkt_vlan:
+ pkt.add_protocol(vlan.vlan(cfi=pkt_vlan.cfi,
+ ethertype=pkt_vlan.ethertype,
+ pcp=pkt_vlan.pcp,
+ vid=pkt_vlan.vid))
pkt.add_protocol(arp.arp(opcode=arp.ARP_REPLY,
src_mac=hw_addr,
src_ip=ip_addr,
msg = ev.msg
LOG.debug("packet-in msg %s", msg)
datapath = msg.datapath
+ if self.br is None:
+ LOG.info(_("No bridge is set"))
+ return
+ if self.br.datapath.id != datapath.id:
+ LOG.info(_("Unknown bridge %(dpid)s ours %(ours)s"),
+ {"dpid": datapath.id, "ours": self.br.datapath.id})
+ return
ofp = datapath.ofproto
- ofpp = datapath.ofproto_parser
port = msg.match['in_port']
+ metadata = msg.match.get('metadata')
pkt = packet.Packet(msg.data)
LOG.info(_("packet-in dpid %(dpid)s in_port %(port)s pkt %(pkt)s"),
{'dpid': dpid_lib.dpid_to_str(datapath.id),
'port': port, 'pkt': pkt})
- pkt_vlan = None
- pkt_arp = None
+
+ if metadata is None:
+ LOG.info(_("drop non tenant packet"))
+ return
+ network = metadata & meta.NETWORK_MASK
pkt_ethernet = pkt.get_protocol(ethernet.ethernet)
if not pkt_ethernet:
- LOG.info(_("non-ethernet packet"))
- else:
- pkt_vlan = pkt.get_protocol(vlan.vlan)
- if not pkt_vlan:
- LOG.info(_("non-vlan packet"))
- if pkt_vlan:
- network = pkt_vlan.vid
- pkt_arp = pkt.get_protocol(arp.arp)
- if not pkt_arp:
- LOG.info(_("drop non-arp packet"))
- return
- else:
- # drop an unknown packet.
- LOG.info(_("drop unknown packet"))
+ LOG.info(_("drop non-ethernet packet"))
+ return
+ pkt_vlan = pkt.get_protocol(vlan.vlan)
+ pkt_arp = pkt.get_protocol(arp.arp)
+ if not pkt_arp:
+ LOG.info(_("drop non-arp packet"))
return
arptbl = self._arp_tbl.get(network)
return
else:
LOG.info(_("unknown network %s"), network)
+
# add a flow to skip a packet-in to a controller.
- match = ofpp.OFPMatch(eth_type=ether.ETH_TYPE_ARP,
- vlan_vid=network | ofp.OFPVID_PRESENT,
- arp_op=arp.ARP_REQUEST,
- arp_tpa=pkt_arp.dst_ip)
- self._add_flow_to_avoid_unknown_packet(datapath, match)
+ self.br.arp_passthrough(network=network, tpa=pkt_arp.dst_ip)
# send an unknown arp packet to the table.
self._send_unknown_packet(msg, port, ofp.OFPP_TABLE)
--- /dev/null
+# Copyright (C) 2014 VA Linux Systems Japan K.K.
+# Copyright (C) 2014 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.
+
+LOCAL_VLAN_MIN = 1
+LOCAL_VLAN_MAX = 0xfff
+LOCAL_VLAN_MASK = 0xfff
--- /dev/null
+# Copyright (C) 2014 VA Linux Systems Japan K.K.
+# Copyright (C) 2014 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.
+
+"""
+OpenFlow1.3 flow table for OFAgent
+
+* requirements
+** plain OpenFlow 1.3. no vendor extensions.
+
+* legends
+ xxx: network id (agent internal use)
+ yyy: segment id (vlan id, gre key, ...)
+ a,b,c: tunnel port (tun_ofports, map[net_id].tun_ofports)
+ i,j,k: vm port (map[net_id].vif_ports[vif_id].ofport)
+ x,y,z: physical port (int_ofports)
+ N: tunnel type (0 for TYPE_GRE, 1 for TYPE_xxx, ...)
+ iii: unknown ip address
+ uuu: unicast l2 address
+
+* tables (in order)
+ CHECK_IN_PORT
+ TUNNEL_IN+N
+ PHYS_IN
+ LOCAL_IN
+ ARP_PASSTHROUGH
+ ARP_RESPONDER
+ TUNNEL_OUT
+ LOCAL_OUT
+ PHYS_OUT
+ TUNNEL_FLOOD+N
+ PHYS_FLOOD
+ LOCAL_FLOOD
+
+* CHECK_IN_PORT
+
+ for each vm ports:
+ // check_in_port_add_local_port, check_in_port_delete_port
+ in_port=i, write_metadata(LOCAL|xxx),goto(LOCAL_IN)
+ TYPE_GRE
+ for each tunnel ports:
+ // check_in_port_add_tunnel_port, check_in_port_delete_port
+ in_port=a, goto(TUNNEL_IN+N)
+ TYPE_VLAN
+ for each networks ports:
+ // provision_tenant_physnet, reclaim_tenant_physnet
+ in_port=x,vlan_vid=present|yyy, write_metadata(xxx),goto(PHYS_IN)
+ TYPE_FLAT
+ // provision_tenant_physnet, reclaim_tenant_physnet
+ in_port=x, write_metadata(xxx),goto(PHYS_IN)
+ default drop
+
+* TUNNEL_IN+N (per tunnel types) tunnel -> network
+
+ for each networks:
+ // provision_tenant_tunnel, reclaim_tenant_tunnel
+ tun_id=yyy, write_metadata(xxx),goto(TUNNEL_OUT)
+
+ default drop
+
+* PHYS_IN
+ default goto(TUNNEL_OUT)
+
+* LOCAL_IN
+ default goto(next_table)
+
+* ARP_PASSTHROUGH
+ for each unknown tpa:
+ // arp_passthrough
+ arp,arp_op=request,metadata=xxx,tpa=iii, idle_timeout=5, goto(TUNNEL_OUT)
+ default goto(next_table)
+
+* ARP_RESPONDER
+ arp,arp_op=request, output:controller
+ default goto(next_table)
+
+* TUNNEL_OUT
+ TYPE_GRE
+ // !FLOODING_ENTRY
+ // install_tunnel_output, delete_tunnel_output
+ metadata=LOCAL|xxx,eth_dst=uuu set_tunnel(yyy),output:a
+
+ default goto(next table)
+
+* LOCAL_OUT
+ for each known destinations:
+ // local_out_add_port, local_out_delete_port
+ metadata=xxx,eth_dst=uuu output:i
+ default goto(next table)
+
+* PHYS_OUT
+
+ NOTE(yamamoto): currently this table is always empty.
+
+ default goto(next table)
+
+* TUNNEL_FLOOD+N. (per tunnel types)
+
+ network -> tunnel/vlan
+ output to tunnel/physical ports
+ "next table" might be LOCAL_OUT
+ TYPE_GRE
+ for each networks:
+ // FLOODING_ENTRY
+ // install_tunnel_output, delete_tunnel_output
+ metadata=LOCAL|xxx, set_tunnel(yyy),output:a,b,c,goto(next table)
+
+ default goto(next table)
+
+* PHYS_FLOOD
+
+ TYPE_VLAN
+ for each networks:
+ // provision_tenant_physnet, reclaim_tenant_physnet
+ metadata=LOCAL|xxx, push_vlan:0x8100,set_field:present|yyy->vlan_vid,
+ output:x,pop_vlan,goto(next table)
+ TYPE_FLAT
+ for each networks:
+ // provision_tenant_physnet, reclaim_tenant_physnet
+ metadata=LOCAL|xxx, output:x,goto(next table)
+
+ default goto(next table)
+
+* LOCAL_FLOOD
+
+ for each networks:
+ // local_flood_update, local_flood_delete
+ metadata=xxx, output:i,j,k
+ or
+ metadata=xxx,eth_dst=broadcast, output:i,j,k
+
+ default drop
+
+* references
+** OVS agent https://wiki.openstack.org/wiki/Ovs-flow-logic
+*** we use metadata instead of "internal" VLANs
+*** we don't want to use NX learn action
+"""
+
+from ryu.lib.packet import arp
+from ryu.ofproto import ether
+
+from neutron.plugins.common import constants as p_const
+import neutron.plugins.ofagent.agent.metadata as meta
+from neutron.plugins.ofagent.agent import ofswitch
+from neutron.plugins.ofagent.agent import tables
+
+
+class OFAgentIntegrationBridge(ofswitch.OpenFlowSwitch):
+ """ofagent br-int specific logic."""
+
+ def setup_default_table(self):
+ self.delete_flows()
+
+ self.install_default_drop(tables.CHECK_IN_PORT)
+
+ for t in tables.TUNNEL_IN.values():
+ self.install_default_drop(t)
+ self.install_default_goto(tables.PHYS_IN, tables.TUNNEL_OUT)
+ self.install_default_goto_next(tables.LOCAL_IN)
+ self.install_default_goto_next(tables.ARP_PASSTHROUGH)
+ self.install_arp_responder(tables.ARP_RESPONDER)
+
+ self.install_default_goto_next(tables.TUNNEL_OUT)
+ self.install_default_goto_next(tables.LOCAL_OUT)
+ self.install_default_goto_next(tables.PHYS_OUT)
+
+ for t in tables.TUNNEL_FLOOD.values():
+ self.install_default_goto_next(t)
+ self.install_default_goto_next(tables.PHYS_FLOOD)
+ self.install_default_drop(tables.LOCAL_FLOOD)
+
+ def install_arp_responder(self, table_id):
+ (dp, ofp, ofpp) = self._get_dp()
+ match = ofpp.OFPMatch(eth_type=ether.ETH_TYPE_ARP,
+ arp_op=arp.ARP_REQUEST)
+ actions = [ofpp.OFPActionOutput(ofp.OFPP_CONTROLLER)]
+ instructions = [
+ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions)]
+ msg = ofpp.OFPFlowMod(dp,
+ table_id=table_id,
+ priority=1,
+ match=match,
+ instructions=instructions)
+ self._send_msg(msg)
+ self.install_default_goto_next(table_id)
+
+ def install_tunnel_output(self, table_id,
+ network, segmentation_id,
+ ports, goto_next, **additional_matches):
+ (dp, ofp, ofpp) = self._get_dp()
+ match = ofpp.OFPMatch(metadata=meta.mk_metadata(network, meta.LOCAL),
+ **additional_matches)
+ actions = [ofpp.OFPActionSetField(tunnel_id=segmentation_id)]
+ actions += [ofpp.OFPActionOutput(port=p) for p in ports]
+ instructions = [
+ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions),
+ ]
+ if goto_next:
+ instructions += [
+ ofpp.OFPInstructionGotoTable(table_id=table_id + 1),
+ ]
+ msg = ofpp.OFPFlowMod(dp,
+ table_id=table_id,
+ priority=1,
+ match=match,
+ instructions=instructions)
+ self._send_msg(msg)
+
+ def delete_tunnel_output(self, table_id,
+ network, **additional_matches):
+ (dp, _ofp, ofpp) = self._get_dp()
+ self.delete_flows(table_id=table_id,
+ metadata=meta.mk_metadata(network, meta.LOCAL),
+ **additional_matches)
+
+ def provision_tenant_tunnel(self, network_type, network, segmentation_id):
+ (dp, _ofp, ofpp) = self._get_dp()
+ match = ofpp.OFPMatch(tunnel_id=segmentation_id)
+ metadata = meta.mk_metadata(network)
+ instructions = [
+ ofpp.OFPInstructionWriteMetadata(metadata=metadata[0],
+ metadata_mask=metadata[1]),
+ ofpp.OFPInstructionGotoTable(table_id=tables.TUNNEL_OUT),
+ ]
+ msg = ofpp.OFPFlowMod(dp,
+ table_id=tables.TUNNEL_IN[network_type],
+ priority=1,
+ match=match,
+ instructions=instructions)
+ self._send_msg(msg)
+
+ def reclaim_tenant_tunnel(self, network_type, network, segmentation_id):
+ table_id = tables.TUNNEL_IN[network_type]
+ self.delete_flows(table_id=table_id, tunnel_id=segmentation_id)
+
+ def provision_tenant_physnet(self, network_type, network,
+ segmentation_id, phys_port):
+ """for vlan and flat."""
+ assert(network_type in [p_const.TYPE_VLAN, p_const.TYPE_FLAT])
+ (dp, ofp, ofpp) = self._get_dp()
+
+ # inbound
+ metadata = meta.mk_metadata(network)
+ instructions = [
+ ofpp.OFPInstructionWriteMetadata(metadata=metadata[0],
+ metadata_mask=metadata[1])
+ ]
+ if network_type == p_const.TYPE_VLAN:
+ vlan_vid = segmentation_id | ofp.OFPVID_PRESENT
+ match = ofpp.OFPMatch(in_port=phys_port, vlan_vid=vlan_vid)
+ actions = [ofpp.OFPActionPopVlan()]
+ instructions += [ofpp.OFPInstructionActions(
+ ofp.OFPIT_APPLY_ACTIONS, actions)]
+ else:
+ match = ofpp.OFPMatch(in_port=phys_port)
+ instructions += [ofpp.OFPInstructionGotoTable(table_id=tables.PHYS_IN)]
+ msg = ofpp.OFPFlowMod(dp,
+ priority=1,
+ table_id=tables.CHECK_IN_PORT,
+ match=match,
+ instructions=instructions)
+ self._send_msg(msg)
+
+ # outbound
+ match = ofpp.OFPMatch(metadata=meta.mk_metadata(network, meta.LOCAL))
+ if network_type == p_const.TYPE_VLAN:
+ actions = [
+ ofpp.OFPActionPushVlan(),
+ ofpp.OFPActionSetField(vlan_vid=vlan_vid),
+ ]
+ else:
+ actions = []
+ actions += [ofpp.OFPActionOutput(port=phys_port)]
+ if network_type == p_const.TYPE_VLAN:
+ actions += [ofpp.OFPActionPopVlan()]
+ instructions = [
+ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions),
+ ofpp.OFPInstructionGotoTable(table_id=tables.PHYS_FLOOD + 1),
+ ]
+ msg = ofpp.OFPFlowMod(dp,
+ priority=1,
+ table_id=tables.PHYS_FLOOD,
+ match=match,
+ instructions=instructions)
+ self._send_msg(msg)
+
+ def reclaim_tenant_physnet(self, network_type, network,
+ segmentation_id, phys_port):
+ (_dp, ofp, _ofpp) = self._get_dp()
+ vlan_vid = segmentation_id | ofp.OFPVID_PRESENT
+ if network_type == p_const.TYPE_VLAN:
+ self.delete_flows(table_id=tables.CHECK_IN_PORT,
+ in_port=phys_port, vlan_vid=vlan_vid)
+ else:
+ self.delete_flows(table_id=tables.CHECK_IN_PORT,
+ in_port=phys_port)
+ self.delete_flows(table_id=tables.PHYS_FLOOD,
+ metadata=meta.mk_metadata(network))
+
+ def check_in_port_add_tunnel_port(self, network_type, port):
+ (dp, _ofp, ofpp) = self._get_dp()
+ match = ofpp.OFPMatch(in_port=port)
+ instructions = [
+ ofpp.OFPInstructionGotoTable(
+ table_id=tables.TUNNEL_IN[network_type])
+ ]
+ msg = ofpp.OFPFlowMod(dp,
+ table_id=tables.CHECK_IN_PORT,
+ priority=1,
+ match=match,
+ instructions=instructions)
+ self._send_msg(msg)
+
+ def check_in_port_add_local_port(self, network, port):
+ (dp, ofp, ofpp) = self._get_dp()
+ match = ofpp.OFPMatch(in_port=port)
+ metadata = meta.mk_metadata(network, meta.LOCAL)
+ instructions = [
+ ofpp.OFPInstructionWriteMetadata(metadata=metadata[0],
+ metadata_mask=metadata[1]),
+ ofpp.OFPInstructionGotoTable(table_id=tables.LOCAL_IN),
+ ]
+ msg = ofpp.OFPFlowMod(dp,
+ table_id=tables.CHECK_IN_PORT,
+ priority=1,
+ match=match,
+ instructions=instructions)
+ self._send_msg(msg)
+
+ def check_in_port_delete_port(self, port):
+ self.delete_flows(table_id=tables.CHECK_IN_PORT, in_port=port)
+
+ def local_flood_update(self, network, ports, flood_unicast):
+ (dp, ofp, ofpp) = self._get_dp()
+ match_all = ofpp.OFPMatch(metadata=meta.mk_metadata(network))
+ match_multicast = ofpp.OFPMatch(metadata=meta.mk_metadata(network),
+ eth_dst=('01:00:00:00:00:00',
+ '01:00:00:00:00:00'))
+ if flood_unicast:
+ match_add = match_all
+ match_del = match_multicast
+ else:
+ match_add = match_multicast
+ match_del = match_all
+ actions = [ofpp.OFPActionOutput(port=p) for p in ports]
+ instructions = [
+ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions),
+ ]
+ msg = ofpp.OFPFlowMod(dp,
+ table_id=tables.LOCAL_FLOOD,
+ priority=1,
+ match=match_add,
+ instructions=instructions)
+ self._send_msg(msg)
+ self.delete_flows(table_id=tables.LOCAL_FLOOD, strict=True,
+ priority=1, match=match_del)
+
+ def local_flood_delete(self, network):
+ self.delete_flows(table_id=tables.LOCAL_FLOOD,
+ metadata=meta.mk_metadata(network))
+
+ def local_out_add_port(self, network, port, mac):
+ (dp, ofp, ofpp) = self._get_dp()
+ match = ofpp.OFPMatch(metadata=meta.mk_metadata(network), eth_dst=mac)
+ actions = [ofpp.OFPActionOutput(port=port)]
+ instructions = [
+ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions),
+ ]
+ msg = ofpp.OFPFlowMod(dp,
+ table_id=tables.LOCAL_OUT,
+ priority=1,
+ match=match,
+ instructions=instructions)
+ self._send_msg(msg)
+
+ def local_out_delete_port(self, network, mac):
+ self.delete_flows(table_id=tables.LOCAL_OUT,
+ metadata=meta.mk_metadata(network), eth_dst=mac)
+
+ def arp_passthrough(self, network, tpa):
+ (dp, ofp, ofpp) = self._get_dp()
+ match = ofpp.OFPMatch(metadata=meta.mk_metadata(network),
+ eth_type=ether.ETH_TYPE_ARP,
+ arp_op=arp.ARP_REQUEST,
+ arp_tpa=tpa)
+ instructions = [
+ ofpp.OFPInstructionGotoTable(table_id=tables.TUNNEL_OUT)]
+ msg = ofpp.OFPFlowMod(dp,
+ table_id=tables.ARP_PASSTHROUGH,
+ priority=1,
+ idle_timeout=5,
+ match=match,
+ instructions=instructions)
+ self._send_msg(msg)
--- /dev/null
+# Copyright (C) 2014 VA Linux Systems Japan K.K.
+# Copyright (C) 2014 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.ofagent.agent import constants as const
+
+
+# metadata mask
+NETWORK_MASK = const.LOCAL_VLAN_MASK
+LOCAL = 0x10000 # the packet came from local vm ports
+
+
+def mk_metadata(network, flags=0):
+ return (flags | network, flags | NETWORK_MASK)
# Copyright (C) 2014 VA Linux Systems Japan K.K.
+# Copyright (C) 2014 YAMAMOTO Takashi <yamamoto at valinux co jp>
# Based on openvswitch agent.
#
# Copyright 2011 VMware, Inc.
from ryu.controller import handler
from ryu.controller import ofp_event
from ryu.lib import hub
-from ryu.lib.packet import arp
-from ryu.ofproto import ether
from ryu.ofproto import ofproto_v1_3 as ryu_ofp13
from neutron.agent import l2population_rpc
from neutron.openstack.common import loopingcall
from neutron.plugins.common import constants as p_const
from neutron.plugins.ofagent.agent import arp_lib
+from neutron.plugins.ofagent.agent import constants as ofa_const
+from neutron.plugins.ofagent.agent import flows
from neutron.plugins.ofagent.agent import ports
+from neutron.plugins.ofagent.agent import tables
from neutron.plugins.ofagent.common import config # noqa
from neutron.plugins.openvswitch.common import constants
LOG = logging.getLogger(__name__)
-# A placeholder for dead vlans.
-DEAD_VLAN_TAG = str(n_const.MAX_VLAN_TAG + 1)
-
# A class to represent a VIF (i.e., a port that has 'iface-id' and 'vif-mac'
# attributes set).
class LocalVLANMapping:
def __init__(self, vlan, network_type, physical_network, segmentation_id,
vif_ports=None):
+ assert(isinstance(vlan, (int, long)))
if vif_ports is None:
vif_ports = {}
self.vlan = vlan
self.segmentation_id))
-class OVSBridge(ovs_lib.OVSBridge):
+class Bridge(flows.OFAgentIntegrationBridge, ovs_lib.OVSBridge):
def __init__(self, br_name, root_helper, ryuapp):
- super(OVSBridge, self).__init__(br_name, root_helper)
+ super(Bridge, self).__init__(br_name, root_helper)
self.datapath_id = None
self.datapath = None
- self.ofparser = None
self.ryuapp = ryuapp
+ self.set_app(ryuapp)
def find_datapath_id(self):
self.datapath_id = self.get_datapath_id()
LOG.error(_('Agent terminated!: Failed to get a datapath.'))
raise SystemExit(1)
time.sleep(1)
- self.ofparser = self.datapath.ofproto_parser
+ self.set_dp(self.datapath)
def setup_ofp(self, controller_names=None,
protocols='OpenFlow13',
cfg.CONF.set_default('ip_lib_force_root', True)
agent = OFANeutronAgent(ryuapp, **agent_config)
+ self.arplib.set_bridge(agent.int_br)
# Start everything.
LOG.info(_("Agent initialized successfully, now running... "))
# 1.1 Support Security Group RPC
RPC_API_VERSION = '1.1'
- def __init__(self, ryuapp, integ_br, tun_br, local_ip,
+ def __init__(self, ryuapp, integ_br, local_ip,
bridge_mappings, root_helper,
polling_interval, tunnel_types=None,
veth_mtu=None):
:param ryuapp: object of the ryu app.
: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.
:param bridge_mappings: mappings from physical network name to bridge.
:param root_helper: utility to use when running shell cmds.
self.ryuapp = ryuapp
self.veth_mtu = veth_mtu
self.root_helper = root_helper
- self.available_local_vlans = set(xrange(n_const.MIN_VLAN_TAG,
- n_const.MAX_VLAN_TAG))
+ # TODO(yamamoto): Remove this VLAN leftover
+ self.available_local_vlans = set(xrange(ofa_const.LOCAL_VLAN_MIN,
+ ofa_const.LOCAL_VLAN_MAX))
self.tunnel_types = tunnel_types or []
self.agent_state = {
'binary': 'neutron-ofa-agent',
# Keep track of int_br's device count for use by _report_state()
self.int_br_device_count = 0
- self.int_br = OVSBridge(integ_br, self.root_helper, self.ryuapp)
+ self.int_br = Bridge(integ_br, self.root_helper, self.ryuapp)
# Stores port update notifications for processing in main loop
self.updated_ports = set()
self.setup_rpc()
self.setup_integration_br()
self.setup_physical_bridges(bridge_mappings)
self.local_vlan_map = {}
- self.tun_br_ofports = {p_const.TYPE_GRE: {},
- p_const.TYPE_VXLAN: {}}
-
+ self.tun_ofports = {}
+ for t in tables.TUNNEL_TYPES:
+ self.tun_ofports[t] = {}
self.polling_interval = polling_interval
self.enable_tunneling = bool(self.tunnel_types)
self.tunnel_count = 0
self.vxlan_udp_port = cfg.CONF.AGENT.vxlan_udp_port
self.dont_fragment = cfg.CONF.AGENT.dont_fragment
- if self.enable_tunneling:
- self.setup_tunnel_br(tun_br)
# Security group agent support
self.sg_agent = OFASecurityGroupAgent(self.context,
LOG.warn(_("Unable to create tunnel port. Invalid remote IP: %s"),
ip_address)
- def ryu_send_msg(self, msg):
- result = ryu_api.send_msg(self.ryuapp, msg)
- LOG.info(_("ryu send_msg() result: %s"), result)
-
def setup_rpc(self):
mac = self.int_br.get_local_port_mac()
self.agent_id = '%s%s' % ('ovs', (mac.replace(":", "")))
self.local_vlan_map):
agent_ports.pop(self.local_ip, None)
if len(agent_ports):
- self.fdb_add_tun(context, self.tun_br, lvm, agent_ports,
- self.tun_br_ofports)
+ self.fdb_add_tun(context, self.int_br, lvm, agent_ports,
+ self.tun_ofports)
def fdb_remove(self, context, fdb_entries):
LOG.debug("fdb_remove received")
self.local_vlan_map):
agent_ports.pop(self.local_ip, None)
if len(agent_ports):
- self.fdb_remove_tun(context, self.tun_br, lvm, agent_ports,
- self.tun_br_ofports)
-
- def _add_fdb_flooding_flow(self, br, lvm):
- datapath = br.datapath
- ofp = datapath.ofproto
- ofpp = datapath.ofproto_parser
- match = ofpp.OFPMatch(
- vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT)
- actions = [ofpp.OFPActionPopVlan(),
- ofpp.OFPActionSetField(
- tunnel_id=int(lvm.segmentation_id))]
- for tun_ofport in lvm.tun_ofports:
- actions.append(ofpp.OFPActionOutput(int(tun_ofport), 0))
- instructions = [ofpp.OFPInstructionActions(
- ofp.OFPIT_APPLY_ACTIONS, actions)]
- msg = ofpp.OFPFlowMod(datapath,
- table_id=constants.FLOOD_TO_TUN,
- command=ofp.OFPFC_ADD,
- priority=1,
- match=match, instructions=instructions)
- self.ryu_send_msg(msg)
+ self.fdb_remove_tun(context, self.int_br, lvm, agent_ports,
+ self.tun_ofports)
def add_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
- datapath = br.datapath
- ofp = datapath.ofproto
- ofpp = datapath.ofproto_parser
if port_info == n_const.FLOODING_ENTRY:
lvm.tun_ofports.add(ofport)
- self._add_fdb_flooding_flow(br, lvm)
+ br.install_tunnel_output(
+ tables.TUNNEL_FLOOD[lvm.network_type],
+ lvm.vlan, lvm.segmentation_id,
+ lvm.tun_ofports, goto_next=True)
else:
self.ryuapp.add_arp_table_entry(
lvm.vlan, port_info[1], port_info[0])
- match = ofpp.OFPMatch(
- vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT,
- eth_dst=port_info[0])
- actions = [ofpp.OFPActionPopVlan(),
- ofpp.OFPActionSetField(
- tunnel_id=int(lvm.segmentation_id)),
- ofpp.OFPActionOutput(int(ofport), 0)]
- instructions = [ofpp.OFPInstructionActions(
- ofp.OFPIT_APPLY_ACTIONS, actions)]
- msg = ofpp.OFPFlowMod(datapath,
- table_id=constants.UCAST_TO_TUN,
- command=ofp.OFPFC_ADD,
- priority=2,
- match=match, instructions=instructions)
- self.ryu_send_msg(msg)
+ br.install_tunnel_output(
+ tables.TUNNEL_OUT,
+ lvm.vlan, lvm.segmentation_id,
+ set([ofport]), goto_next=False, eth_dst=port_info[0])
def del_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
- datapath = br.datapath
- ofp = datapath.ofproto
- ofpp = datapath.ofproto_parser
if port_info == n_const.FLOODING_ENTRY:
lvm.tun_ofports.remove(ofport)
if len(lvm.tun_ofports) > 0:
- self._add_fdb_flooding_flow(br, lvm)
+ br.install_tunnel_output(
+ tables.TUNNEL_FLOOD[lvm.network_type],
+ lvm.vlan, lvm.segmentation_id,
+ lvm.tun_ofports, goto_next=True)
else:
- # This local vlan doesn't require any more tunelling
- match = ofpp.OFPMatch(
- vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT)
- msg = ofpp.OFPFlowMod(datapath,
- table_id=constants.FLOOD_TO_TUN,
- command=ofp.OFPFC_DELETE,
- out_group=ofp.OFPG_ANY,
- out_port=ofp.OFPP_ANY,
- match=match)
- self.ryu_send_msg(msg)
+ br.delete_tunnel_output(
+ tables.TUNNEL_FLOOD[lvm.network_type],
+ lvm.vlan)
else:
self.ryuapp.del_arp_table_entry(lvm.vlan, port_info[1])
- match = ofpp.OFPMatch(
- vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT,
- eth_dst=port_info[0])
- msg = ofpp.OFPFlowMod(datapath,
- table_id=constants.UCAST_TO_TUN,
- command=ofp.OFPFC_DELETE,
- out_group=ofp.OFPG_ANY,
- out_port=ofp.OFPP_ANY,
- match=match)
- self.ryu_send_msg(msg)
+ br.delete_tunnel_output(tables.TUNNEL_OUT,
+ lvm.vlan, eth_dst=port_info[0])
def setup_entry_for_arp_reply(self, br, action, local_vid, mac_address,
ip_address):
def _fdb_chg_ip(self, context, fdb_entries):
LOG.debug("update chg_ip received")
- self.fdb_chg_ip_tun(context, self.tun_br, fdb_entries, self.local_ip,
+ self.fdb_chg_ip_tun(context, self.int_br, fdb_entries, self.local_ip,
self.local_vlan_map)
- def _provision_local_vlan_inbound_for_tunnel(self, lvid, network_type,
- segmentation_id):
- br = self.tun_br
- match = br.ofparser.OFPMatch(
- tunnel_id=int(segmentation_id))
- actions = [
- br.ofparser.OFPActionPushVlan(),
- br.ofparser.OFPActionSetField(
- vlan_vid=int(lvid) | ryu_ofp13.OFPVID_PRESENT)]
- instructions = [
- br.ofparser.OFPInstructionActions(
- ryu_ofp13.OFPIT_APPLY_ACTIONS, actions),
- br.ofparser.OFPInstructionGotoTable(
- table_id=constants.LEARN_FROM_TUN)]
- msg = br.ofparser.OFPFlowMod(
- br.datapath,
- table_id=constants.TUN_TABLE[network_type],
- priority=1,
- match=match,
- instructions=instructions)
- self.ryu_send_msg(msg)
-
- def _local_vlan_for_tunnel(self, lvid, network_type, segmentation_id):
- self._provision_local_vlan_inbound_for_tunnel(lvid, network_type,
- segmentation_id)
-
- def _provision_local_vlan_outbound(self, lvid, vlan_vid, physical_network):
- br = self.phys_brs[physical_network]
- datapath = br.datapath
- ofp = datapath.ofproto
- ofpp = datapath.ofproto_parser
- match = ofpp.OFPMatch(in_port=int(self.phys_ofports[physical_network]),
- vlan_vid=int(lvid) | ofp.OFPVID_PRESENT)
- if vlan_vid == ofp.OFPVID_NONE:
- actions = [ofpp.OFPActionPopVlan()]
- else:
- actions = [ofpp.OFPActionSetField(vlan_vid=vlan_vid)]
- actions += [ofpp.OFPActionOutput(ofp.OFPP_NORMAL, 0)]
- instructions = [
- ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions),
- ]
- msg = ofpp.OFPFlowMod(datapath, priority=4, match=match,
- instructions=instructions)
- self.ryu_send_msg(msg)
-
- def _provision_local_vlan_inbound(self, lvid, vlan_vid, physical_network):
- datapath = self.int_br.datapath
- ofp = datapath.ofproto
- ofpp = datapath.ofproto_parser
- match = ofpp.OFPMatch(in_port=int(self.int_ofports[physical_network]),
- vlan_vid=vlan_vid)
- if vlan_vid == ofp.OFPVID_NONE:
- actions = [ofpp.OFPActionPushVlan()]
- else:
- actions = []
- actions += [
- ofpp.OFPActionSetField(vlan_vid=int(lvid) | ofp.OFPVID_PRESENT),
- ofpp.OFPActionOutput(ofp.OFPP_NORMAL, 0),
- ]
- instructions = [
- ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions),
- ]
- msg = ofpp.OFPFlowMod(datapath, priority=3, match=match,
- instructions=instructions)
- self.ryu_send_msg(msg)
-
- def _local_vlan_for_flat(self, lvid, physical_network):
- vlan_vid = ryu_ofp13.OFPVID_NONE
- self._provision_local_vlan_outbound(lvid, vlan_vid, physical_network)
- self._provision_local_vlan_inbound(lvid, vlan_vid, physical_network)
-
- def _local_vlan_for_vlan(self, lvid, physical_network, segmentation_id):
- vlan_vid = int(segmentation_id) | ryu_ofp13.OFPVID_PRESENT
- self._provision_local_vlan_outbound(lvid, vlan_vid, physical_network)
- self._provision_local_vlan_inbound(lvid, vlan_vid, physical_network)
-
def provision_local_vlan(self, net_uuid, network_type, physical_network,
segmentation_id):
"""Provisions a local VLAN.
if network_type in constants.TUNNEL_NETWORK_TYPES:
if self.enable_tunneling:
- self._local_vlan_for_tunnel(lvid, network_type,
- segmentation_id)
+ self.int_br.provision_tenant_tunnel(network_type, lvid,
+ segmentation_id)
else:
LOG.error(_("Cannot provision %(network_type)s network for "
"net-id=%(net_uuid)s - tunneling disabled"),
{'network_type': network_type,
'net_uuid': net_uuid})
- elif network_type == p_const.TYPE_FLAT:
- if physical_network in self.phys_brs:
- self._local_vlan_for_flat(lvid, physical_network)
+ elif network_type in [p_const.TYPE_VLAN, p_const.TYPE_FLAT]:
+ if physical_network in self.int_ofports:
+ phys_port = self.int_ofports[physical_network]
+ self.int_br.provision_tenant_physnet(network_type, lvid,
+ segmentation_id,
+ phys_port)
else:
- LOG.error(_("Cannot provision flat network for "
- "net-id=%(net_uuid)s - no bridge for "
- "physical_network %(physical_network)s"),
- {'net_uuid': net_uuid,
- 'physical_network': physical_network})
- elif network_type == p_const.TYPE_VLAN:
- if physical_network in self.phys_brs:
- self._local_vlan_for_vlan(lvid, physical_network,
- segmentation_id)
- else:
- LOG.error(_("Cannot provision VLAN network for "
+ LOG.error(_("Cannot provision %(network_type)s network for "
"net-id=%(net_uuid)s - no bridge for "
"physical_network %(physical_network)s"),
- {'net_uuid': net_uuid,
+ {'network_type': network_type,
+ 'net_uuid': net_uuid,
'physical_network': physical_network})
elif network_type == p_const.TYPE_LOCAL:
# no flows needed for local networks
{'network_type': network_type,
'net_uuid': net_uuid})
- def _reclaim_local_vlan_outbound(self, lvm):
- br = self.phys_brs[lvm.physical_network]
- datapath = br.datapath
- ofp = datapath.ofproto
- ofpp = datapath.ofproto_parser
- match = ofpp.OFPMatch(
- in_port=int(self.phys_ofports[lvm.physical_network]),
- vlan_vid=int(lvm.vlan) | ofp.OFPVID_PRESENT)
- msg = ofpp.OFPFlowMod(datapath, table_id=ofp.OFPTT_ALL,
- command=ofp.OFPFC_DELETE, out_group=ofp.OFPG_ANY,
- out_port=ofp.OFPP_ANY, match=match)
- self.ryu_send_msg(msg)
-
- def _reclaim_local_vlan_inbound(self, lvm):
- datapath = self.int_br.datapath
- ofp = datapath.ofproto
- ofpp = datapath.ofproto_parser
- if lvm.network_type == p_const.TYPE_FLAT:
- vid = ofp.OFPVID_NONE
- else: # p_const.TYPE_VLAN
- vid = lvm.segmentation_id | ofp.OFPVID_PRESENT
- match = ofpp.OFPMatch(
- in_port=int(self.int_ofports[lvm.physical_network]),
- vlan_vid=vid)
- msg = ofpp.OFPFlowMod(datapath, table_id=ofp.OFPTT_ALL,
- command=ofp.OFPFC_DELETE, out_group=ofp.OFPG_ANY,
- out_port=ofp.OFPP_ANY, match=match)
- self.ryu_send_msg(msg)
-
def reclaim_local_vlan(self, net_uuid):
"""Reclaim a local VLAN.
if lvm.network_type in constants.TUNNEL_NETWORK_TYPES:
if self.enable_tunneling:
- match = self.tun_br.ofparser.OFPMatch(
- tunnel_id=int(lvm.segmentation_id))
- msg = self.tun_br.ofparser.OFPFlowMod(
- self.tun_br.datapath,
- table_id=constants.TUN_TABLE[lvm.network_type],
- command=ryu_ofp13.OFPFC_DELETE,
- out_group=ryu_ofp13.OFPG_ANY,
- out_port=ryu_ofp13.OFPP_ANY,
- match=match)
- self.ryu_send_msg(msg)
- match = self.tun_br.ofparser.OFPMatch(
- vlan_vid=int(lvm.vlan) | ryu_ofp13.OFPVID_PRESENT)
- msg = self.tun_br.ofparser.OFPFlowMod(
- self.tun_br.datapath,
- table_id=ryu_ofp13.OFPTT_ALL,
- command=ryu_ofp13.OFPFC_DELETE,
- out_group=ryu_ofp13.OFPG_ANY,
- out_port=ryu_ofp13.OFPP_ANY,
- match=match)
- self.ryu_send_msg(msg)
+ self.int_br.reclaim_tenant_tunnel(lvm.network_type, lvm.vlan,
+ lvm.segmentation_id)
# Try to remove tunnel ports if not used by other networks
for ofport in lvm.tun_ofports:
- self.cleanup_tunnel_port(self.tun_br, ofport,
+ self.cleanup_tunnel_port(self.int_br, ofport,
lvm.network_type)
- elif lvm.network_type in (p_const.TYPE_FLAT, p_const.TYPE_VLAN):
- if lvm.physical_network in self.phys_brs:
- self._reclaim_local_vlan_outbound(lvm)
- self._reclaim_local_vlan_inbound(lvm)
+ elif lvm.network_type in [p_const.TYPE_FLAT, p_const.TYPE_VLAN]:
+ phys_port = self.int_ofports[lvm.physical_network]
+ self.int_br.reclaim_tenant_physnet(lvm.network_type, lvm.vlan,
+ lvm.segmentation_id, phys_port)
elif lvm.network_type == p_const.TYPE_LOCAL:
# no flows needed for local networks
pass
self.provision_local_vlan(net_uuid, network_type,
physical_network, segmentation_id)
lvm = self.local_vlan_map[net_uuid]
+
lvm.vif_ports[port.normalized_port_name()] = port
- # Do not bind a port if it's already bound
- cur_tag = self.int_br.db_get_val("Port", port.port_name, "tag")
- if cur_tag != str(lvm.vlan):
- self.int_br.set_db_attribute("Port", port.port_name, "tag",
- str(lvm.vlan))
- if port.ofport != -1:
- match = self.int_br.ofparser.OFPMatch(in_port=port.ofport)
- msg = self.int_br.ofparser.OFPFlowMod(
- self.int_br.datapath,
- table_id=ryu_ofp13.OFPTT_ALL,
- command=ryu_ofp13.OFPFC_DELETE,
- out_group=ryu_ofp13.OFPG_ANY,
- out_port=ryu_ofp13.OFPP_ANY,
- match=match)
- self.ryu_send_msg(msg)
+ self.int_br.check_in_port_add_local_port(lvm.vlan, port.ofport)
+
+ # if any of vif mac is unknown, flood unicasts as well
+ flood_unicast = any(map(lambda x: x.vif_mac is None,
+ lvm.vif_ports.values()))
+ ofports = (vp.ofport for vp in lvm.vif_ports.values())
+ self.int_br.local_flood_update(lvm.vlan, ofports, flood_unicast)
+ if port.vif_mac is None:
+ return
+ self.int_br.local_out_add_port(lvm.vlan, port.ofport, port.vif_mac)
def port_unbound(self, vif_id, net_uuid=None):
"""Unbind port.
return
lvm = self.local_vlan_map[net_uuid]
- lvm.vif_ports.pop(vif_id, None)
+ port = lvm.vif_ports.pop(vif_id, None)
+ self.int_br.check_in_port_delete_port(port.ofport)
if not lvm.vif_ports:
self.reclaim_local_vlan(net_uuid)
+ if port.vif_mac is None:
+ return
+ self.int_br.local_out_delete_port(lvm.vlan, port.vif_mac)
def port_dead(self, port):
"""Once a port has no binding, put it on the "dead vlan".
:param port: a ovs_lib.VifPort object.
"""
- # Don't kill a port if it's already dead
- cur_tag = self.int_br.db_get_val("Port", port.port_name, "tag")
- if cur_tag != DEAD_VLAN_TAG:
- self.int_br.set_db_attribute("Port", port.port_name, "tag",
- DEAD_VLAN_TAG)
- match = self.int_br.ofparser.OFPMatch(in_port=port.ofport)
- msg = self.int_br.ofparser.OFPFlowMod(self.int_br.datapath,
- priority=2, match=match)
- self.ryu_send_msg(msg)
+ pass
def setup_integration_br(self):
"""Setup the integration bridge.
-
- Create patch ports and remove all existing flows.
-
- :param bridge_name: the name of the integration bridge.
- :returns: the integration bridge
"""
- self.int_br.setup_ofp()
- self.int_br.delete_port(cfg.CONF.OVS.int_peer_patch_port)
- msg = self.int_br.ofparser.OFPFlowMod(self.int_br.datapath,
- table_id=ryu_ofp13.OFPTT_ALL,
- command=ryu_ofp13.OFPFC_DELETE,
- out_group=ryu_ofp13.OFPG_ANY,
- out_port=ryu_ofp13.OFPP_ANY)
- self.ryu_send_msg(msg)
- # switch all traffic using L2 learning
- actions = [self.int_br.ofparser.OFPActionOutput(
- ryu_ofp13.OFPP_NORMAL, 0)]
- instructions = [self.int_br.ofparser.OFPInstructionActions(
- ryu_ofp13.OFPIT_APPLY_ACTIONS,
- actions)]
- msg = self.int_br.ofparser.OFPFlowMod(self.int_br.datapath,
- priority=1,
- instructions=instructions)
- self.ryu_send_msg(msg)
-
- def _tun_br_sort_incoming_traffic_depend_in_port(self, br):
- match = br.ofparser.OFPMatch(
- in_port=int(self.patch_int_ofport))
- instructions = [br.ofparser.OFPInstructionGotoTable(
- table_id=constants.PATCH_LV_TO_TUN)]
- msg = br.ofparser.OFPFlowMod(br.datapath,
- priority=1,
- match=match,
- instructions=instructions)
- self.ryu_send_msg(msg)
- msg = br.ofparser.OFPFlowMod(br.datapath, priority=0)
- self.ryu_send_msg(msg)
-
- def _tun_br_output_arp_packet_to_controller(self, br):
- datapath = br.datapath
- ofp = datapath.ofproto
- ofpp = datapath.ofproto_parser
- match = ofpp.OFPMatch(eth_type=ether.ETH_TYPE_ARP,
- arp_op=arp.ARP_REQUEST)
- actions = [ofpp.OFPActionOutput(ofp.OFPP_CONTROLLER)]
- instructions = [
- ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions)]
- msg = ofpp.OFPFlowMod(datapath,
- table_id=constants.PATCH_LV_TO_TUN,
- priority=10,
- match=match,
- instructions=instructions)
- self.ryu_send_msg(msg)
-
- def _tun_br_goto_table_ucast_unicast(self, br):
- match = br.ofparser.OFPMatch(eth_dst=('00:00:00:00:00:00',
- '01:00:00:00:00:00'))
- instructions = [br.ofparser.OFPInstructionGotoTable(
- table_id=constants.UCAST_TO_TUN)]
- msg = br.ofparser.OFPFlowMod(br.datapath,
- table_id=constants.PATCH_LV_TO_TUN,
- priority=0,
- match=match,
- instructions=instructions)
- self.ryu_send_msg(msg)
-
- def _tun_br_goto_table_flood_broad_multi_cast(self, br):
- match = br.ofparser.OFPMatch(eth_dst=('01:00:00:00:00:00',
- '01:00:00:00:00:00'))
- instructions = [br.ofparser.OFPInstructionGotoTable(
- table_id=constants.FLOOD_TO_TUN)]
- msg = br.ofparser.OFPFlowMod(br.datapath,
- table_id=constants.PATCH_LV_TO_TUN,
- priority=0,
- match=match,
- instructions=instructions)
- self.ryu_send_msg(msg)
-
- def _tun_br_set_table_tun_by_tunnel_type(self, br):
- for tunnel_type in constants.TUNNEL_NETWORK_TYPES:
- msg = br.ofparser.OFPFlowMod(
- br.datapath,
- table_id=constants.TUN_TABLE[tunnel_type],
- priority=0)
- self.ryu_send_msg(msg)
-
- def _tun_br_output_patch_int(self, br):
- actions = [br.ofparser.OFPActionOutput(
- int(self.patch_int_ofport), 0)]
- instructions = [br.ofparser.OFPInstructionActions(
- ryu_ofp13.OFPIT_APPLY_ACTIONS,
- actions)]
- msg = br.ofparser.OFPFlowMod(br.datapath,
- table_id=constants.LEARN_FROM_TUN,
- priority=1,
- instructions=instructions)
- self.ryu_send_msg(msg)
-
- def _tun_br_goto_table_flood_unknown_unicast(self, br):
- instructions = [br.ofparser.OFPInstructionGotoTable(
- table_id=constants.FLOOD_TO_TUN)]
- msg = br.ofparser.OFPFlowMod(br.datapath,
- table_id=constants.UCAST_TO_TUN,
- priority=0,
- instructions=instructions)
- self.ryu_send_msg(msg)
-
- def _tun_br_default_drop(self, br):
- msg = br.ofparser.OFPFlowMod(
- br.datapath,
- table_id=constants.FLOOD_TO_TUN,
- priority=0)
- self.ryu_send_msg(msg)
-
- def setup_tunnel_br(self, tun_br):
- """Setup the tunnel bridge.
-
- Creates tunnel bridge, and links it to the integration bridge
- using a patch port.
-
- :param tun_br: the name of the tunnel bridge.
- """
- self.tun_br = OVSBridge(tun_br, self.root_helper, self.ryuapp)
- self.tun_br.reset_bridge()
- self.tun_br.setup_ofp()
- 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(
- cfg.CONF.OVS.tun_peer_patch_port, cfg.CONF.OVS.int_peer_patch_port)
- if int(self.patch_tun_ofport) < 0 or int(self.patch_int_ofport) < 0:
- LOG.error(_("Failed to create OVS patch port. Cannot have "
- "tunneling enabled on this agent, since this version "
- "of OVS does not support tunnels or patch ports. "
- "Agent terminated!"))
- raise SystemExit(1)
- msg = self.tun_br.ofparser.OFPFlowMod(self.tun_br.datapath,
- table_id=ryu_ofp13.OFPTT_ALL,
- command=ryu_ofp13.OFPFC_DELETE,
- out_group=ryu_ofp13.OFPG_ANY,
- out_port=ryu_ofp13.OFPP_ANY)
- self.ryu_send_msg(msg)
-
- self._tun_br_sort_incoming_traffic_depend_in_port(self.tun_br)
- self._tun_br_output_arp_packet_to_controller(self.tun_br)
- self._tun_br_goto_table_ucast_unicast(self.tun_br)
- self._tun_br_goto_table_flood_broad_multi_cast(self.tun_br)
- self._tun_br_set_table_tun_by_tunnel_type(self.tun_br)
- self._tun_br_output_patch_int(self.tun_br)
- self._tun_br_goto_table_flood_unknown_unicast(self.tun_br)
- self._tun_br_default_drop(self.tun_br)
+
+ br = self.int_br
+ br.setup_ofp()
+ br.setup_default_table()
def _phys_br_prepare_create_veth(self, br, int_veth_name, phys_veth_name):
self.int_br.delete_port(int_veth_name)
phys_veth_name, physical_network, ip_wrapper):
int_veth, phys_veth = ip_wrapper.add_veth(int_veth_name,
phys_veth_name)
- self.int_ofports[physical_network] = self.int_br.add_port(int_veth)
- self.phys_ofports[physical_network] = br.add_port(phys_veth)
+ int_br = self.int_br
+ self.int_ofports[physical_network] = int(int_br.add_port(int_veth))
+ self.phys_ofports[physical_network] = int(br.add_port(phys_veth))
return (int_veth, phys_veth)
- def _phys_br_block_untranslated_traffic(self, br, physical_network):
- match = self.int_br.ofparser.OFPMatch(in_port=int(
- self.int_ofports[physical_network]))
- msg = self.int_br.ofparser.OFPFlowMod(self.int_br.datapath,
- priority=2, match=match)
- self.ryu_send_msg(msg)
- match = br.ofparser.OFPMatch(in_port=int(
- self.phys_ofports[physical_network]))
- msg = br.ofparser.OFPFlowMod(br.datapath, priority=2, match=match)
- self.ryu_send_msg(msg)
-
def _phys_br_enable_veth_to_pass_traffic(self, int_veth, phys_veth):
# enable veth to pass traffic
int_veth.link.set_up()
phys_veth_name,
physical_network,
ip_wrapper)
- self._phys_br_block_untranslated_traffic(br, physical_network)
self._phys_br_enable_veth_to_pass_traffic(int_veth, phys_veth)
def setup_physical_bridges(self, bridge_mappings):
{'physical_network': physical_network,
'bridge': bridge})
raise SystemExit(1)
- br = OVSBridge(bridge, self.root_helper, self.ryuapp)
- br.setup_ofp()
- msg = br.ofparser.OFPFlowMod(br.datapath,
- table_id=ryu_ofp13.OFPTT_ALL,
- command=ryu_ofp13.OFPFC_DELETE,
- out_group=ryu_ofp13.OFPG_ANY,
- out_port=ryu_ofp13.OFPP_ANY)
- self.ryu_send_msg(msg)
- actions = [br.ofparser.OFPActionOutput(ryu_ofp13.OFPP_NORMAL, 0)]
- instructions = [br.ofparser.OFPInstructionActions(
- ryu_ofp13.OFPIT_APPLY_ACTIONS,
- actions)]
- msg = br.ofparser.OFPFlowMod(br.datapath,
- priority=1,
- instructions=instructions)
- self.ryu_send_msg(msg)
+ br = Bridge(bridge, self.root_helper, self.ryuapp)
self.phys_brs[physical_network] = br
self._phys_br_patch_physical_bridge_with_integration_bridge(
port_info = {'current': cur_ports}
if updated_ports is None:
updated_ports = set()
- updated_ports.update(self._find_lost_vlan_port(registered_ports))
if updated_ports:
# Some updated ports might have been removed in the
# meanwhile, and therefore should not be processed.
port_info['removed'] = registered_ports - cur_ports
return port_info
- def _find_lost_vlan_port(self, registered_ports):
- """Return ports which have lost their vlan tag.
-
- The returned value is a set of port ids of the ports concerned by a
- vlan tag loss.
- """
- # TODO(yamamoto): stop using ovsdb
- # an idea is to use metadata instead of tagged vlans.
- # cf. blueprint ofagent-merge-bridges
- port_tags = self.int_br.get_port_tag_dict()
- changed_ports = set()
- for lvm in self.local_vlan_map.values():
- for port in registered_ports:
- if (
- port in lvm.vif_ports
- and port in port_tags
- and port_tags[port] != lvm.vlan
- ):
- LOG.info(
- _("Port '%(port_name)s' has lost "
- "its vlan tag '%(vlan_tag)d'!"),
- {'port_name': port,
- 'vlan_tag': lvm.vlan}
- )
- changed_ports.add(port)
- return changed_ports
-
def treat_vif_port(self, vif_port, port_id, network_id, network_type,
physical_network, segmentation_id, admin_state_up):
if vif_port:
LOG.debug(_("No VIF port for port %s defined on agent."), port_id)
def _setup_tunnel_port(self, br, port_name, remote_ip, tunnel_type):
- ofport = br.add_tunnel_port(port_name,
- remote_ip,
- self.local_ip,
- tunnel_type,
- self.vxlan_udp_port,
- self.dont_fragment)
- ofport_int = -1
+ ofport_str = br.add_tunnel_port(port_name,
+ remote_ip,
+ self.local_ip,
+ tunnel_type,
+ self.vxlan_udp_port,
+ self.dont_fragment)
+ ofport = -1
try:
- ofport_int = int(ofport)
+ ofport = int(ofport_str)
except (TypeError, ValueError):
LOG.exception(_("ofport should have a value that can be "
"interpreted as an integer"))
- if ofport_int < 0:
+ if ofport < 0:
LOG.error(_("Failed to set-up %(type)s tunnel port to %(ip)s"),
{'type': tunnel_type, 'ip': remote_ip})
return 0
- self.tun_br_ofports[tunnel_type][remote_ip] = ofport
- # Add flow in default table to resubmit to the right
- # tunelling table (lvid will be set in the latter)
- match = br.ofparser.OFPMatch(in_port=int(ofport))
- instructions = [br.ofparser.OFPInstructionGotoTable(
- table_id=constants.TUN_TABLE[tunnel_type])]
- msg = br.ofparser.OFPFlowMod(br.datapath,
- priority=1,
- match=match,
- instructions=instructions)
- self.ryu_send_msg(msg)
+ self.tun_ofports[tunnel_type][remote_ip] = ofport
+ br.check_in_port_add_tunnel_port(tunnel_type, ofport)
return ofport
def setup_tunnel_port(self, br, remote_ip, network_type):
return ofport
def _remove_tunnel_port(self, br, tun_ofport, tunnel_type):
- datapath = br.datapath
- ofp = datapath.ofproto
- ofpp = datapath.ofproto_parser
- for remote_ip, ofport in self.tun_br_ofports[tunnel_type].items():
+ for remote_ip, ofport in self.tun_ofports[tunnel_type].items():
if ofport == tun_ofport:
+ br.check_in_port_delete_port(ofport)
port_name = self._create_tunnel_port_name(tunnel_type,
remote_ip)
if port_name:
br.delete_port(port_name)
- match = ofpp.OFPMatch(in_port=int(ofport))
- msg = ofpp.OFPFlowMod(datapath,
- command=ofp.OFPFC_DELETE,
- out_group=ofp.OFPG_ANY,
- out_port=ofp.OFPP_ANY,
- match=match)
- self.ryu_send_msg(msg)
- self.tun_br_ofports[tunnel_type].pop(remote_ip, None)
+ self.tun_ofports[tunnel_type].pop(remote_ip, None)
def cleanup_tunnel_port(self, br, tun_ofport, tunnel_type):
# Check if this tunnel port is still used
if 'port_id' in details:
LOG.info(_("Port %(device)s updated. Details: %(details)s"),
{'device': device, 'details': details})
+ port.vif_mac = details.get('mac_address')
self.treat_vif_port(port, details['port_id'],
details['network_id'],
details['network_type'],
kwargs = dict(
integ_br=config.OVS.integration_bridge,
- tun_br=config.OVS.tunnel_bridge,
local_ip=config.OVS.local_ip,
bridge_mappings=bridge_mappings,
root_helper=config.AGENT.root_helper,
--- /dev/null
+# Copyright (C) 2014 VA Linux Systems Japan K.K.
+# Copyright (C) 2014 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 ryu.app.ofctl import api as ofctl_api
+
+
+class OpenFlowSwitch(object):
+ def __init__(self, *args, **kwargs):
+ super(OpenFlowSwitch, self).__init__(*args, **kwargs)
+ self._dp = None
+ # logically app doesn't belong here. just for convenience.
+ self._app = None
+
+ def set_dp(self, dp):
+ self._dp = dp
+
+ def set_app(self, app):
+ self._app = app
+
+ def _get_dp(self):
+ """a convenient method for openflow message composers"""
+ dp = self._dp
+ return (dp, dp.ofproto, dp.ofproto_parser)
+
+ def _send_msg(self, msg):
+ return ofctl_api.send_msg(self._app, msg)
+
+ def delete_flows(self, table_id=None, strict=False, priority=0,
+ match=None, **match_kwargs):
+ (dp, ofp, ofpp) = self._get_dp()
+ if table_id is None:
+ table_id = ofp.OFPTT_ALL
+ if match is None:
+ match = ofpp.OFPMatch(**match_kwargs)
+ if strict:
+ cmd = ofp.OFPFC_DELETE_STRICT
+ else:
+ cmd = ofp.OFPFC_DELETE
+ msg = ofpp.OFPFlowMod(dp,
+ command=cmd,
+ table_id=table_id,
+ match=match,
+ priority=priority,
+ out_group=ofp.OFPG_ANY,
+ out_port=ofp.OFPP_ANY)
+ self._send_msg(msg)
+
+ def install_default_drop(self, table_id):
+ (dp, _ofp, ofpp) = self._get_dp()
+ msg = ofpp.OFPFlowMod(dp,
+ table_id=table_id,
+ priority=0)
+ self._send_msg(msg)
+
+ def install_default_goto(self, table_id, dest_table_id):
+ (dp, _ofp, ofpp) = self._get_dp()
+ instructions = [ofpp.OFPInstructionGotoTable(table_id=dest_table_id)]
+ msg = ofpp.OFPFlowMod(dp,
+ table_id=table_id,
+ priority=0,
+ instructions=instructions)
+ self._send_msg(msg)
+
+ def install_default_goto_next(self, table_id):
+ self.install_default_goto(table_id, table_id + 1)
# Copyright (C) 2014 VA Linux Systems Japan K.K.
+# Copyright (C) 2014 YAMAMOTO Takashi <yamamoto at valinux co jp>
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-#
-# @author: YAMAMOTO Takashi, VA Linux Systems Japan K.K.
class OFPort(object):
class Port(OFPort):
+ def __init__(self, *args, **kwargs):
+ super(Port, self).__init__(*args, **kwargs)
+ self.vif_mac = None
+
def is_neutron_port(self):
"""Return True if the port looks like a neutron port."""
return _is_neutron_port(self.port_name)
--- /dev/null
+# Copyright (C) 2014 VA Linux Systems Japan K.K.
+# Copyright (C) 2014 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.common import constants as p_const
+
+
+def _seq():
+ """Yield sequential numbers starting from 0."""
+ i = 0
+ while True:
+ yield i
+ i += 1
+
+_table_id_gen = _seq()
+
+
+def _table_id():
+ """A simple table id allocator."""
+ return _table_id_gen.next()
+
+# Supported tunnel types.
+TUNNEL_TYPES = [
+ p_const.TYPE_GRE,
+ p_const.TYPE_VXLAN,
+]
+
+# Reversed version of TUNNEL_TYPES.
+TUNNEL_TYPE_IDX = dict((t, TUNNEL_TYPES.index(t)) for t in TUNNEL_TYPES)
+
+# We use sequential table ids starting from 0.
+# We don't hardcode values here to avoid manual reassignments eg. when adding
+# a new tunnel type.
+# See a big comment in flows.py for how each tables are used.
+CHECK_IN_PORT = _table_id()
+TUNNEL_IN = {}
+for t in TUNNEL_TYPES:
+ TUNNEL_IN[t] = _table_id()
+PHYS_IN = _table_id()
+LOCAL_IN = _table_id()
+ARP_PASSTHROUGH = _table_id()
+ARP_RESPONDER = _table_id()
+TUNNEL_OUT = _table_id()
+LOCAL_OUT = _table_id()
+PHYS_OUT = _table_id()
+TUNNEL_FLOOD = {}
+for t in TUNNEL_TYPES:
+ TUNNEL_FLOOD[t] = _table_id()
+PHYS_FLOOD = _table_id()
+LOCAL_FLOOD = _table_id()
ryu_packet_mod.ethernet = ethernet
ryu_packet_mod.vlan = vlan
ryu_ofproto_mod = ryu_mod.ofproto
+ ether = _Mod('ryu.ofproto.ether')
ofp = _Mod('ryu.ofproto.ofproto_v1_3')
ofpp = _Mod('ryu.ofproto.ofproto_v1_3_parser')
+ ryu_ofproto_mod.ether = ether
ryu_ofproto_mod.ofproto_v1_3 = ofp
ryu_ofproto_mod.ofproto_v1_3_parser = ofpp
ryu_app_mod = ryu_mod.app
'ryu.lib.packet.ethernet': ethernet,
'ryu.lib.packet.vlan': vlan,
'ryu.ofproto': ryu_ofproto_mod,
+ 'ryu.ofproto.ether': ether,
'ryu.ofproto.ofproto_v1_3': ofp,
'ryu.ofproto.ofproto_v1_3_parser': ofpp,
'ryu.app': ryu_app_mod,
from neutron.tests.unit.ofagent import fake_oflib
-class OFAAgentTestBase(base.BaseTestCase):
-
- _AGENT_NAME = 'neutron.plugins.ofagent.agent.ofa_neutron_agent'
+class OFATestBase(base.BaseTestCase):
def setUp(self):
self.fake_oflib_of = fake_oflib.patch_fake_oflib_of()
self.fake_oflib_of.start()
self.addCleanup(self.fake_oflib_of.stop)
- self.mod_agent = importutils.import_module(self._AGENT_NAME)
- super(OFAAgentTestBase, self).setUp()
- self.ryuapp = mock.Mock()
-
- def setup_config(self):
- cfg.CONF.set_default('firewall_driver',
- 'neutron.agent.firewall.NoopFirewallDriver',
- group='SECURITYGROUP')
- cfg.CONF.register_cli_opts([
- cfg.StrOpt('ofp-listen-host', default='',
- help='openflow listen host'),
- cfg.IntOpt('ofp-tcp-listen-port', default=6633,
- help='openflow tcp listen port')
- ])
- cfg.CONF.set_override('root_helper', 'fake_helper', group='AGENT')
+ super(OFATestBase, self).setUp()
def _mk_test_dp(self, name):
ofp = importutils.import_module('ryu.ofproto.ofproto_v1_3')
br.ofproto = dp.ofproto
br.ofparser = dp.ofproto_parser
return br
+
+
+class OFAAgentTestBase(OFATestBase):
+
+ _AGENT_NAME = 'neutron.plugins.ofagent.agent.ofa_neutron_agent'
+
+ def setUp(self):
+ super(OFAAgentTestBase, self).setUp()
+ self.mod_agent = importutils.import_module(self._AGENT_NAME)
+ self.ryuapp = mock.Mock()
+
+ def setup_config(self):
+ cfg.CONF.set_default('firewall_driver',
+ 'neutron.agent.firewall.NoopFirewallDriver',
+ group='SECURITYGROUP')
+ cfg.CONF.register_cli_opts([
+ cfg.StrOpt('ofp-listen-host', default='',
+ help='openflow listen host'),
+ cfg.IntOpt('ofp-tcp-listen-port', default=6633,
+ help='openflow tcp listen port')
+ ])
+ cfg.CONF.set_override('root_helper', 'fake_helper', group='AGENT')
import mock
from neutron.openstack.common import importutils
+import neutron.plugins.ofagent.agent.metadata as meta
from neutron.tests.unit.ofagent import ofa_test_base
self.packet_mod = mock.Mock()
self.proto_ethernet_mod = mock.Mock()
self.proto_vlan_mod = mock.Mock()
- self.proto_vlan_mod.vid = self.nets[0].net
+ self.proto_vlan_mod.vid = 999
self.proto_arp_mod = mock.Mock()
self.fake_get_protocol = mock.Mock(return_value=self.proto_vlan_mod)
self.packet_mod.get_protocol = self.fake_get_protocol
self.msg_data = 'test_message_data'
self.msg.data = self.msg_data
self.ev.msg = self.msg
- self.msg.match = {'in_port': self.inport}
+ self.msg.match = {'in_port': self.inport,
+ 'metadata': meta.LOCAL | self.nets[0].net}
class TestArpLib(OFAAgentTestCase):
self._fake_get_protocol_ethernet = True
self._fake_get_protocol_vlan = True
self._fake_get_protocol_arp = True
+ self.br = mock.Mock(datapath=self.datapath)
+ self.arplib.set_bridge(self.br)
def test__send_unknown_packet_no_buffer(self):
in_port = 3
else:
return
- def test_packet_in_handler(self):
+ def _test_packet_in_handler(self):
self.arplib._arp_tbl = {
self.nets[0].net: {self.nets[0].ip: self.nets[0].mac}}
with contextlib.nested(
mock.patch.object(self.arplib, '_respond_arp',
return_value=True),
- mock.patch.object(self.arplib,
- '_add_flow_to_avoid_unknown_packet'),
+ mock.patch.object(self.br,
+ 'arp_passthrough'),
mock.patch.object(self.arplib,
'_send_unknown_packet'),
) as (res_arp_fn, add_flow_fn, send_unknown_pk_fn):
res_arp_fn.assert_called_once_with(
self.datapath, self.inport,
self.arplib._arp_tbl[self.nets[0].net],
- self.proto_ethernet_mod, self.proto_vlan_mod, self.proto_arp_mod)
+ self.proto_ethernet_mod,
+ self.proto_vlan_mod if self._fake_get_protocol_vlan else None,
+ self.proto_arp_mod)
- def _test_packet_in_handler(self):
+ def _test_packet_in_handler_drop(self):
self.arplib._arp_tbl = {
self.nets[0].net: {self.nets[0].ip: self.nets[0].mac}}
with contextlib.nested(
mock.patch.object(self.arplib, '_respond_arp',
return_value=True),
- mock.patch.object(self.arplib,
- '_add_flow_to_avoid_unknown_packet'),
+ mock.patch.object(self.br, 'arp_passthrough'),
mock.patch.object(self.arplib,
'_send_unknown_packet'),
) as (res_arp_fn, add_flow_fn, send_unknown_pk_fn):
self.assertFalse(send_unknown_pk_fn.call_count)
self.assertFalse(res_arp_fn.call_count)
+ def test_packet_in_handler(self):
+ self._test_packet_in_handler()
+
def test_packet_in_handler_non_ethernet(self):
self._fake_get_protocol_ethernet = False
- self._test_packet_in_handler()
+ self._test_packet_in_handler_drop()
def test_packet_in_handler_non_vlan(self):
self._fake_get_protocol_vlan = False
def test_packet_in_handler_non_arp(self):
self._fake_get_protocol_arp = False
- self._test_packet_in_handler()
+ self._test_packet_in_handler_drop()
def test_packet_in_handler_unknown_network(self):
self.arplib._arp_tbl = {
with contextlib.nested(
mock.patch.object(self.arplib, '_respond_arp',
return_value=False),
- mock.patch.object(self.arplib,
- '_add_flow_to_avoid_unknown_packet'),
+ mock.patch.object(self.br, 'arp_passthrough'),
mock.patch.object(self.arplib,
'_send_unknown_packet'),
) as (res_arp_fn, add_flow_fn, send_unknown_pk_fn):
self.arplib.packet_in_handler(self.ev)
add_flow_fn.assert_called_once_with(
- self.datapath,
- self.datapath.ofproto_parser.OFPMatch(
- eth_type=self.ethernet.ETH_TYPE_ARP,
- vlan_vid=self.proto_vlan_mod.vid |
- self.datapath.ofproto.OFPVID_PRESENT,
- arp_op=self.arp.ARP_REQUEST,
- arp_tpa=self.proto_arp_mod.dst_ip))
+ network=self.nets[0].net,
+ tpa=self.proto_arp_mod.dst_ip)
send_unknown_pk_fn.assert_called_once_with(
self.ev.msg, self.msg.match['in_port'],
self.datapath.ofproto.OFPP_TABLE)
--- /dev/null
+# Copyright (C) 2014 VA Linux Systems Japan K.K.
+# Copyright (C) 2014 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.openstack.common import importutils
+import neutron.plugins.ofagent.agent.metadata as meta
+from neutron.tests.unit.ofagent import ofa_test_base
+
+
+class TestOFAgentFlows(ofa_test_base.OFATestBase):
+
+ _MOD = 'neutron.plugins.ofagent.agent.flows'
+
+ def setUp(self):
+ super(TestOFAgentFlows, self).setUp()
+ self.mod = importutils.import_module(self._MOD)
+ self.br = self.mod.OFAgentIntegrationBridge()
+ self.br.set_dp(self._mk_test_dp("dp"))
+
+ def test_setup_default_table(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.setup_default_table()
+ (dp, ofp, ofpp) = br._get_dp()
+ arp = importutils.import_module('ryu.lib.packet.arp')
+ ether = importutils.import_module('ryu.ofproto.ether')
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, command=ofp.OFPFC_DELETE,
+ match=ofpp.OFPMatch(), out_group=ofp.OFPG_ANY,
+ out_port=ofp.OFPP_ANY, priority=0, table_id=ofp.OFPTT_ALL)),
+ call(ofpp.OFPFlowMod(dp, priority=0, table_id=0)),
+ call(ofpp.OFPFlowMod(dp, priority=0, table_id=1)),
+ call(ofpp.OFPFlowMod(dp, priority=0, table_id=2)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=7)],
+ priority=0, table_id=3)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=5)],
+ priority=0, table_id=4)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=6)],
+ priority=0, table_id=5)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
+ [ofpp.OFPActionOutput(ofp.OFPP_CONTROLLER)])],
+ match=ofpp.OFPMatch(arp_op=arp.ARP_REQUEST,
+ eth_type=ether.ETH_TYPE_ARP), priority=1, table_id=6)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=7)],
+ priority=0, table_id=6)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=8)],
+ priority=0, table_id=7)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=9)],
+ priority=0, table_id=8)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=10)],
+ priority=0, table_id=9)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=11)],
+ priority=0, table_id=10)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=12)],
+ priority=0, table_id=11)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=13)],
+ priority=0, table_id=12)),
+ call(ofpp.OFPFlowMod(dp, priority=0, table_id=13)),
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_install_arp_responder(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.install_arp_responder(table_id=99)
+ (dp, ofp, ofpp) = br._get_dp()
+ arp = importutils.import_module('ryu.lib.packet.arp')
+ ether = importutils.import_module('ryu.ofproto.ether')
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
+ [ofpp.OFPActionOutput(ofp.OFPP_CONTROLLER)])],
+ match=ofpp.OFPMatch(arp_op=arp.ARP_REQUEST,
+ eth_type=ether.ETH_TYPE_ARP), priority=1, table_id=99)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=100)],
+ priority=0, table_id=99)),
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_install_tunnel_output(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.install_tunnel_output(table_id=110, network=111,
+ segmentation_id=112, ports=[113, 114],
+ goto_next=True)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
+ [ofpp.OFPActionSetField(tunnel_id=112),
+ ofpp.OFPActionOutput(port=113),
+ ofpp.OFPActionOutput(port=114)]),
+ ofpp.OFPInstructionGotoTable(table_id=111)],
+ match=ofpp.OFPMatch(metadata=
+ meta.mk_metadata(111, meta.LOCAL)),
+ priority=1, table_id=110))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_delete_tunnel_output(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.delete_tunnel_output(table_id=110, network=111)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, command=ofp.OFPFC_DELETE,
+ match=ofpp.OFPMatch(metadata=
+ meta.mk_metadata(111, meta.LOCAL)),
+ out_group=ofp.OFPG_ANY,
+ out_port=ofp.OFPP_ANY, priority=0, table_id=110))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_provision_tenant_tunnel(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.provision_tenant_tunnel(network_type="gre", network=150,
+ segmentation_id=151)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionWriteMetadata(metadata=150,
+ metadata_mask=meta.NETWORK_MASK),
+ ofpp.OFPInstructionGotoTable(table_id=7)],
+ match=ofpp.OFPMatch(tunnel_id=151), priority=1, table_id=1))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_reclaim_tenant_tunnel(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.reclaim_tenant_tunnel(network_type="gre", network=150,
+ segmentation_id=151)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, command=ofp.OFPFC_DELETE,
+ match=ofpp.OFPMatch(tunnel_id=151), out_group=ofp.OFPG_ANY,
+ out_port=ofp.OFPP_ANY, priority=0, table_id=1))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_provision_tenant_physnet(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.provision_tenant_physnet(network_type="vlan", network=150,
+ segmentation_id=151, phys_port=99)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionWriteMetadata(metadata=150,
+ metadata_mask=meta.NETWORK_MASK),
+ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [
+ ofpp.OFPActionPopVlan()]),
+ ofpp.OFPInstructionGotoTable(table_id=3)],
+ match=ofpp.OFPMatch(in_port=99,
+ vlan_vid=151 | ofp.OFPVID_PRESENT),
+ priority=1, table_id=0)),
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [
+ ofpp.OFPActionPushVlan(),
+ ofpp.OFPActionSetField(vlan_vid=151 | ofp.OFPVID_PRESENT),
+ ofpp.OFPActionOutput(port=99), ofpp.OFPActionPopVlan()]),
+ ofpp.OFPInstructionGotoTable(table_id=13)],
+ match=ofpp.OFPMatch(metadata=
+ meta.mk_metadata(150, meta.LOCAL)),
+ priority=1, table_id=12))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_reclaim_tenant_physnet(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.reclaim_tenant_physnet(network_type="vlan", network=150,
+ segmentation_id=151, phys_port=99)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, command=ofp.OFPFC_DELETE,
+ match=ofpp.OFPMatch(in_port=99,
+ vlan_vid=151 | ofp.OFPVID_PRESENT),
+ out_group=ofp.OFPG_ANY, out_port=ofp.OFPP_ANY, priority=0,
+ table_id=0)),
+ call(ofpp.OFPFlowMod(dp, command=ofp.OFPFC_DELETE,
+ match=ofpp.OFPMatch(metadata=meta.mk_metadata(150)),
+ out_group=ofp.OFPG_ANY, out_port=ofp.OFPP_ANY, priority=0,
+ table_id=12))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_check_in_port_add_tunnel_port(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.check_in_port_add_tunnel_port(network_type="gre", port=99)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp,
+ instructions=[ofpp.OFPInstructionGotoTable(table_id=1)],
+ match=ofpp.OFPMatch(in_port=99), priority=1, table_id=0))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_check_in_port_add_local_port(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.check_in_port_add_local_port(network=123, port=99)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp,
+ instructions=[
+ ofpp.OFPInstructionWriteMetadata(
+ metadata=meta.LOCAL | 123,
+ metadata_mask=meta.LOCAL | meta.NETWORK_MASK),
+ ofpp.OFPInstructionGotoTable(table_id=4)],
+ match=ofpp.OFPMatch(in_port=99), priority=1, table_id=0))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_check_in_port_delete_port(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.check_in_port_delete_port(port=99)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, command=ofp.OFPFC_DELETE,
+ match=ofpp.OFPMatch(in_port=99), out_group=ofp.OFPG_ANY,
+ out_port=ofp.OFPP_ANY, priority=0, table_id=0))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_local_flood_update(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.local_flood_update(network=1234, ports=[1, 2, 3],
+ flood_unicast=True)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp,
+ instructions=[ofpp.OFPInstructionActions(
+ ofp.OFPIT_APPLY_ACTIONS, [
+ ofpp.OFPActionOutput(port=1),
+ ofpp.OFPActionOutput(port=2),
+ ofpp.OFPActionOutput(port=3)])],
+ match=ofpp.OFPMatch(metadata=meta.mk_metadata(1234)),
+ priority=1, table_id=13)),
+ call(ofpp.OFPFlowMod(dp, command=ofp.OFPFC_DELETE_STRICT,
+ match=ofpp.OFPMatch(
+ eth_dst=('01:00:00:00:00:00', '01:00:00:00:00:00'),
+ metadata=meta.mk_metadata(1234)),
+ out_group=ofp.OFPG_ANY, out_port=ofp.OFPP_ANY, priority=1,
+ table_id=13))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_local_flood_delete(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.local_flood_delete(network=1234)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, command=ofp.OFPFC_DELETE,
+ match=ofpp.OFPMatch(metadata=meta.mk_metadata(1234)),
+ out_group=ofp.OFPG_ANY, out_port=ofp.OFPP_ANY, priority=0,
+ table_id=13))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_local_out_add_port(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.local_out_add_port(network=1234, port=7,
+ mac='12:34:56:78:9a:bc')
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
+ [ofpp.OFPActionOutput(port=7)])],
+ match=ofpp.OFPMatch(eth_dst="12:34:56:78:9a:bc",
+ metadata=meta.mk_metadata(1234)), priority=1, table_id=8))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_local_out_delete_port(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.local_out_delete_port(network=1234, mac='12:34:56:78:9a:bc')
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, command=ofp.OFPFC_DELETE,
+ match=ofpp.OFPMatch(eth_dst="12:34:56:78:9a:bc",
+ metadata=meta.mk_metadata(1234)), out_group=ofp.OFPG_ANY,
+ out_port=ofp.OFPP_ANY, priority=0, table_id=8))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_arp_passthrough(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.arp_passthrough(network=1234, tpa='192.0.2.1')
+ (dp, ofp, ofpp) = br._get_dp()
+ arp = importutils.import_module('ryu.lib.packet.arp')
+ ether = importutils.import_module('ryu.ofproto.ether')
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, idle_timeout=5,
+ instructions=[ofpp.OFPInstructionGotoTable(table_id=7)],
+ match=ofpp.OFPMatch(arp_op=arp.ARP_REQUEST,
+ arp_tpa="192.0.2.1", eth_type=ether.ETH_TYPE_ARP,
+ metadata=meta.mk_metadata(1234)), priority=1, table_id=5))
+ ]
+ sendmsg.assert_has_calls(expected_calls)
import collections
import contextlib
+import copy
import mock
import netaddr
from neutron.common import constants as n_const
from neutron.openstack.common import importutils
from neutron.plugins.common import constants as p_const
-from neutron.plugins.openvswitch.common import constants
from neutron.tests.unit.ofagent import ofa_test_base
[p_const.TYPE_GRE, p_const.TYPE_VXLAN])
-class TestOFANeutronAgentOVSBridge(ofa_test_base.OFAAgentTestBase):
+class TestOFANeutronAgentBridge(ofa_test_base.OFAAgentTestBase):
def setUp(self):
- super(TestOFANeutronAgentOVSBridge, self).setUp()
+ super(TestOFANeutronAgentBridge, self).setUp()
self.br_name = 'bridge1'
self.root_helper = 'fake_helper'
- self.ovs = self.mod_agent.OVSBridge(
+ self.ovs = self.mod_agent.Bridge(
self.br_name, self.root_helper, self.ryuapp)
def test_find_datapath_id(self):
mock.patch.object(self.mod_agent.OFANeutronAgent,
'setup_integration_br',
return_value=mock.Mock()),
- mock.patch.object(self.mod_agent.OVSBridge,
+ mock.patch.object(self.mod_agent.Bridge,
'get_local_port_mac',
return_value='00:00:00:00:00:01'),
mock.patch('neutron.agent.linux.utils.get_interface_mac',
self.agent.sg_agent = mock.Mock()
self.int_dp = self._mk_test_dp('int_br')
- self.agent.int_br.ofparser = self.int_dp.ofproto_parser
- self.agent.int_br.datapath = self.int_dp
- self.agent.tun_br = self._mk_test_br('tun_br')
+ self.agent.int_br = self._mk_test_br('int_br')
+ self.agent.int_br.set_dp(self.int_dp)
self.agent.phys_brs['phys-net1'] = self._mk_test_br('phys_br1')
self.agent.phys_ofports['phys-net1'] = 777
self.agent.int_ofports['phys-net1'] = 666
tunnel_ip_hex = '%08x' % netaddr.IPAddress(tunnel_ip, version=4)
return '%s-%s' % (tunnel_type, tunnel_ip_hex)
- def _mock_port_bound(self, ofport=None, new_local_vlan=None,
- old_local_vlan=None):
- port_name = 'tap96408df7-16'
- port = _mock_port(True, port_name)
- port.ofport = ofport
- net_uuid = 'my-net-uuid'
- ofp = self.agent.int_br.datapath.ofproto
- ofpp = self.agent.int_br.datapath.ofproto_parser
- expected_msg = ofpp.OFPFlowMod(
- self.agent.int_br.datapath,
- match=ofpp.OFPMatch(in_port=port.ofport),
- table_id=ofp.OFPTT_ALL,
- command=ofp.OFPFC_DELETE,
- out_group=ofp.OFPG_ANY,
- out_port=ofp.OFPP_ANY
- )
- if old_local_vlan is not None:
- self.agent.local_vlan_map[net_uuid] = (
- self.mod_agent.LocalVLANMapping(
- old_local_vlan, None, None, None))
- with contextlib.nested(
- mock.patch.object(self.mod_agent.OVSBridge,
- 'set_db_attribute', return_value=True),
- mock.patch.object(self.mod_agent.OVSBridge,
- 'db_get_val', return_value=str(old_local_vlan)),
- mock.patch.object(self.agent, 'ryu_send_msg')
- ) as (set_ovs_db_func, get_ovs_db_func, ryu_send_msg_func):
- self.agent.port_bound(port, net_uuid, 'local', None, None)
- get_ovs_db_func.assert_called_once_with("Port", mock.ANY, "tag")
- if new_local_vlan != old_local_vlan:
- set_ovs_db_func.assert_called_once_with(
- "Port", mock.ANY, "tag", str(new_local_vlan))
- if ofport != -1:
- ryu_send_msg_func.assert_called_once_with(expected_msg)
- else:
- self.assertFalse(ryu_send_msg_func.called)
- else:
- self.assertFalse(set_ovs_db_func.called)
- self.assertFalse(ryu_send_msg_func.called)
- self.assertTrue(self.agent.local_vlan_map[net_uuid].
- vif_ports[port_name] is port)
-
- def test_port_bound_deletes_flows_for_valid_ofport(self):
- self._mock_port_bound(ofport=1, new_local_vlan=1)
-
- def test_port_bound_ignores_flows_for_invalid_ofport(self):
- self._mock_port_bound(ofport=-1, new_local_vlan=1)
-
- def test_port_bound_does_not_rewire_if_already_bound(self):
- self._mock_port_bound(ofport=-1, new_local_vlan=1, old_local_vlan=1)
-
- def _test_port_dead(self, cur_tag=None):
- port = mock.Mock()
- port.ofport = 1
- ofpp = self.agent.int_br.datapath.ofproto_parser
- expected_msg = ofpp.OFPFlowMod(
- self.agent.int_br.datapath,
- priority=2,
- match=ofpp.OFPMatch(in_port=port.ofport)
- )
- with contextlib.nested(
- mock.patch.object(self.mod_agent.OVSBridge,
- 'set_db_attribute', return_value=True),
- mock.patch.object(self.mod_agent.OVSBridge,
- 'db_get_val', return_value=cur_tag),
- mock.patch.object(self.agent, 'ryu_send_msg')
- ) as (set_ovs_db_func, get_ovs_db_func, ryu_send_msg_func):
- self.agent.port_dead(port)
- get_ovs_db_func.assert_called_once_with("Port", mock.ANY, "tag")
- if cur_tag == self.mod_agent.DEAD_VLAN_TAG:
- self.assertFalse(set_ovs_db_func.called)
- self.assertFalse(ryu_send_msg_func.called)
- else:
- set_ovs_db_func.assert_called_once_with(
- "Port", mock.ANY, "tag", str(self.mod_agent.DEAD_VLAN_TAG))
- ryu_send_msg_func.assert_called_once_with(expected_msg)
-
- def test_port_dead(self):
- self._test_port_dead()
-
- def test_port_dead_with_port_already_dead(self):
- self._test_port_dead(self.mod_agent.DEAD_VLAN_TAG)
-
def mock_scan_ports(self, port_set=None, registered_ports=None,
updated_ports=None, port_tags_dict=None):
port_tags_dict = port_tags_dict or {}
updated_ports)
self.assertEqual(expected, actual)
- def test_update_ports_returns_lost_vlan_port(self):
- port = mock.Mock(port_name='tap00000001-00', ofport=1)
- lvm = self.mod_agent.LocalVLANMapping(
- vlan=1, network_type='1', physical_network=None, segmentation_id=1,
- vif_ports={port.port_name: port})
- local_vlan_map = {'1': lvm}
- port_set = set(['tap00000001-00',
- 'tap00000003-00'])
- registered_ports = set(['tap00000001-00', 'tap00000002-00'])
- port_tags_dict = {'tap00000001-00': []}
- expected = dict(
- added=set(['tap00000003-00']),
- current=set(['tap00000001-00', 'tap00000003-00']),
- removed=set(['tap00000002-00']),
- updated=set(['tap00000001-00'])
- )
- with mock.patch.dict(self.agent.local_vlan_map, local_vlan_map):
- actual = self.mock_scan_ports(
- port_set, registered_ports, port_tags_dict=port_tags_dict)
- self.assertEqual(expected, actual)
-
def test_treat_devices_added_returns_true_for_missing_device(self):
with contextlib.nested(
mock.patch.object(self.agent.plugin_rpc, 'get_device_details',
with contextlib.nested(
mock.patch.object(ip_lib, "device_exists"),
mock.patch.object(utils, "execute"),
- mock.patch.object(self.mod_agent.OVSBridge, "add_port"),
- mock.patch.object(self.mod_agent.OVSBridge, "delete_port"),
- mock.patch.object(self.mod_agent.OVSBridge, "set_protocols"),
- mock.patch.object(self.mod_agent.OVSBridge, "set_controller"),
- mock.patch.object(self.mod_agent.OVSBridge, "get_datapath_id",
+ mock.patch.object(self.mod_agent.Bridge, "add_port"),
+ mock.patch.object(self.mod_agent.Bridge, "delete_port"),
+ mock.patch.object(self.mod_agent.Bridge, "set_protocols"),
+ mock.patch.object(self.mod_agent.Bridge, "set_controller"),
+ mock.patch.object(self.mod_agent.Bridge, "get_datapath_id",
return_value='0xa'),
mock.patch.object(self.agent.int_br, "add_port"),
mock.patch.object(self.agent.int_br, "delete_port"),
mock.call.add_veth('int-br-eth',
'phy-br-eth')]
parent.assert_has_calls(expected_calls, any_order=False)
- self.assertEqual(self.agent.int_ofports["physnet1"],
- "11")
- self.assertEqual(self.agent.phys_ofports["physnet1"],
- "25")
+ self.assertEqual(11, self.agent.int_ofports["physnet1"])
+ self.assertEqual(25, self.agent.phys_ofports["physnet1"])
def test_port_unbound(self):
- with mock.patch.object(self.agent, "reclaim_local_vlan") as reclvl_fn:
+ with contextlib.nested(
+ mock.patch.object(self.agent, "reclaim_local_vlan"),
+ mock.patch.object(self.agent, "get_net_uuid",
+ return_value="netuid12345"),
+ ) as (reclvl_fn, _):
self.agent.enable_tunneling = True
lvm = mock.Mock()
lvm.network_type = "gre"
lvm.vif_ports = {"vif1": mock.Mock()}
self.agent.local_vlan_map["netuid12345"] = lvm
- self.agent.port_unbound("vif1", "netuid12345")
+ self.agent.port_unbound("vif1")
self.assertTrue(reclvl_fn.called)
- reclvl_fn.called = False
-
- lvm.vif_ports = {}
- self.agent.port_unbound("vif1", "netuid12345")
- self.assertEqual(reclvl_fn.call_count, 2)
-
- lvm.vif_ports = {"vif1": mock.Mock()}
- self.agent.port_unbound("vif3", "netuid12345")
- self.assertEqual(reclvl_fn.call_count, 2)
def _prepare_l2_pop_ofports(self):
LVM = collections.namedtuple('LVM', 'net, vlan, segid, ip')
- self.lvms = [LVM(net='net1', vlan=11, segid='21', ip='1.1.1.1'),
- LVM(net='net2', vlan=12, segid='22', ip='2.2.2.2')]
+ self.lvms = [LVM(net='net1', vlan=11, segid=21, ip='1.1.1.1'),
+ LVM(net='net2', vlan=12, segid=22, ip='2.2.2.2')]
self.tunnel_type = 'gre'
self.tun_name1 = self._create_tunnel_port_name(self.lvms[0].ip,
self.tunnel_type)
lvm1.network_type = self.tunnel_type
lvm1.vlan = self.lvms[0].vlan
lvm1.segmentation_id = self.lvms[0].segid
- lvm1.tun_ofports = set(['1'])
+ lvm1.tun_ofports = set([1])
lvm2 = mock.Mock()
lvm2.network_type = self.tunnel_type
lvm2.vlan = self.lvms[1].vlan
lvm2.segmentation_id = self.lvms[1].segid
- lvm2.tun_ofports = set(['1', '2'])
+ lvm2.tun_ofports = set([1, 2])
self.agent.local_vlan_map = {self.lvms[0].net: lvm1,
self.lvms[1].net: lvm2}
- self.agent.tun_br_ofports = {self.tunnel_type:
- {self.lvms[0].ip: '1',
- self.lvms[1].ip: '2'}}
+ self.agent.tun_ofports = {self.tunnel_type:
+ {self.lvms[0].ip: 1,
+ self.lvms[1].ip: 2}}
def test_fdb_ignore_network(self):
self._prepare_l2_pop_ofports()
fdb_entry = {'net3': {}}
with contextlib.nested(
- mock.patch.object(self.agent, 'ryu_send_msg'),
mock.patch.object(self.agent, '_setup_tunnel_port'),
mock.patch.object(self.agent, 'cleanup_tunnel_port')
- ) as (ryu_send_msg_fn, add_tun_fn, clean_tun_fn):
+ ) as (add_tun_fn, clean_tun_fn):
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(add_tun_fn.called)
self.agent.fdb_remove(None, fdb_entry)
self.assertFalse(clean_tun_fn.called)
- self.assertFalse(ryu_send_msg_fn.called)
def test_fdb_ignore_self(self):
self._prepare_l2_pop_ofports()
{'agent_ip':
[['mac', 'ip'],
n_const.FLOODING_ENTRY]}}}
- with mock.patch.object(self.agent.tun_br,
- "defer_apply_on") as defer_fn:
- self.agent.fdb_add(None, fdb_entry)
- self.assertFalse(defer_fn.called)
-
+ with contextlib.nested(
+ mock.patch.object(self.agent.ryuapp, "add_arp_table_entry"),
+ mock.patch.object(self.agent.ryuapp, "del_arp_table_entry"),
+ ) as (add_fn, del_fn):
+ self.agent.fdb_add(None, copy.deepcopy(fdb_entry))
+ self.assertFalse(add_fn.called)
+ self.assertFalse(del_fn.called)
self.agent.fdb_remove(None, fdb_entry)
- self.assertFalse(defer_fn.called)
+ self.assertFalse(add_fn.called)
+ self.assertFalse(del_fn.called)
def test_fdb_add_flows(self):
self._prepare_l2_pop_ofports()
[['mac', 'ip'],
n_const.FLOODING_ENTRY]}}}
with contextlib.nested(
- mock.patch.object(self.agent, 'ryu_send_msg'),
- mock.patch.object(self.agent.tun_br, '_setup_tunnel_port'),
- ) as (ryu_send_msg_fn, add_tun_fn):
- add_tun_fn.return_value = '2'
+ mock.patch.object(self.agent, '_setup_tunnel_port'),
+ mock.patch.object(self.agent.int_br, 'install_tunnel_output'),
+ mock.patch.object(self.agent.int_br, 'delete_tunnel_output'),
+ ) as (add_tun_fn, install_fn, delete_fn):
+ add_tun_fn.return_value = 2
self.agent.fdb_add(None, fdb_entry)
- self.assertEqual(ryu_send_msg_fn.call_count, 2)
+ self.assertEqual(2, install_fn.call_count)
+ expected_calls = [
+ mock.call(7, 11, 21, set([2]), eth_dst='mac', goto_next=False),
+ mock.call(10, 11, 21, set([1, 2]), goto_next=True)
+ ]
+ install_fn.assert_has_calls(expected_calls)
+ self.assertFalse(delete_fn.called)
def test_fdb_del_flows(self):
self._prepare_l2_pop_ofports()
{self.lvms[1].ip:
[['mac', 'ip'],
n_const.FLOODING_ENTRY]}}}
- with mock.patch.object(self.agent,
- 'ryu_send_msg') as ryu_send_msg_fn:
+ with contextlib.nested(
+ mock.patch.object(self.agent.int_br, 'install_tunnel_output'),
+ mock.patch.object(self.agent.int_br, 'delete_tunnel_output'),
+ ) as (install_fn, delete_fn):
self.agent.fdb_remove(None, fdb_entry)
- self.assertEqual(ryu_send_msg_fn.call_count, 3)
+ install_fn.assert_called_once_with(10, 12, 22, set([1]),
+ goto_next=True)
+ delete_fn.assert_called_once_with(7, 12, eth_dst='mac')
def test_fdb_add_port(self):
self._prepare_l2_pop_ofports()
{'network_type': self.tunnel_type,
'segment_id': 'tun1',
'ports': {self.lvms[0].ip: [['mac', 'ip']]}}}
- with contextlib.nested(
- mock.patch.object(self.agent, 'ryu_send_msg'),
- mock.patch.object(self.agent, '_setup_tunnel_port')
- ) as (ryu_send_msg_fn, add_tun_fn):
+ with mock.patch.object(self.agent, '_setup_tunnel_port') as add_tun_fn:
self.agent.fdb_add(None, fdb_entry)
self.assertFalse(add_tun_fn.called)
fdb_entry[self.lvms[0].net]['ports'][tunnel_ip] = [['mac', 'ip']]
self.agent.fdb_add(None, fdb_entry)
add_tun_fn.assert_called_with(
- self.agent.tun_br, tun_name, tunnel_ip, self.tunnel_type)
+ self.agent.int_br, tun_name, tunnel_ip, self.tunnel_type)
def test_fdb_del_port(self):
self._prepare_l2_pop_ofports()
{'network_type': self.tunnel_type,
'segment_id': 'tun2',
'ports': {self.lvms[1].ip: [n_const.FLOODING_ENTRY]}}}
- with contextlib.nested(
- mock.patch.object(self.agent, 'ryu_send_msg'),
- mock.patch.object(self.agent.tun_br, 'delete_port')
- ) as (ryu_send_msg_fn, del_port_fn):
+ with mock.patch.object(self.agent.int_br,
+ 'delete_port') as del_port_fn:
self.agent.fdb_remove(None, fdb_entry)
del_port_fn.assert_called_once_with(self.tun_name2)
'segment_id': 'tun1',
'ports': {self.lvms[0].ip: [['mac1', 'ip1']],
self.lvms[1].ip: [['mac2', 'ip2']]}}}
- with mock.patch.multiple(self.agent,
- ryu_send_msg=mock.DEFAULT,
- setup_tunnel_port=mock.DEFAULT):
+ with mock.patch.object(self.agent, 'setup_tunnel_port'):
self.agent.fdb_add(None, fdb_entry)
calls = [
mock.call(self.agent.local_vlan_map[self.lvms[0].net].vlan,
'segment_id': 'tun1',
'ports': {self.lvms[0].ip: [['mac1', 'ip1']],
self.lvms[1].ip: [['mac2', 'ip2']]}}}
- with mock.patch.multiple(self.agent,
- ryu_send_msg=mock.DEFAULT,
- setup_tunnel_port=mock.DEFAULT):
+ with mock.patch.object(self.agent, 'cleanup_tunnel_port'):
self.agent.fdb_remove(None, fdb_entry)
calls = [
mock.call(self.agent.local_vlan_map[self.lvms[0].net].vlan,
self._prepare_l2_pop_ofports()
self.agent.enable_tunneling = True
with mock.patch.object(
- self.agent.tun_br, 'cleanup_tunnel_port'
- ) as clean_tun_fn:
+ self.agent.int_br, 'delete_port'
+ ) as del_port_fn:
self.agent.reclaim_local_vlan(self.lvms[0].net)
- self.assertFalse(clean_tun_fn.called)
+ self.assertFalse(del_port_fn.called)
def test_recl_lv_port_to_remove(self):
self._prepare_l2_pop_ofports()
self.agent.enable_tunneling = True
- with contextlib.nested(
- mock.patch.object(self.agent.tun_br, 'delete_port'),
- mock.patch.object(self.agent, 'ryu_send_msg')
- ) as (del_port_fn, ryu_send_msg_fn):
+ with mock.patch.object(self.agent.int_br,
+ 'delete_port') as del_port_fn:
self.agent.reclaim_local_vlan(self.lvms[1].net)
del_port_fn.assert_called_once_with(self.tun_name2)
def test__setup_tunnel_port_error_negative(self):
with contextlib.nested(
- mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
+ mock.patch.object(self.agent.int_br, 'add_tunnel_port',
return_value='-1'),
mock.patch.object(self.mod_agent.LOG, 'error')
) as (add_tunnel_port_fn, log_error_fn):
ofport = self.agent._setup_tunnel_port(
- self.agent.tun_br, 'gre-1', 'remote_ip', p_const.TYPE_GRE)
+ self.agent.int_br, 'gre-1', 'remote_ip', p_const.TYPE_GRE)
add_tunnel_port_fn.assert_called_once_with(
'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
self.agent.vxlan_udp_port, self.agent.dont_fragment)
def test__setup_tunnel_port_error_not_int(self):
with contextlib.nested(
- mock.patch.object(self.agent.tun_br, 'add_tunnel_port',
+ mock.patch.object(self.agent.int_br, 'add_tunnel_port',
return_value=None),
mock.patch.object(self.mod_agent.LOG, 'exception'),
mock.patch.object(self.mod_agent.LOG, 'error')
) as (add_tunnel_port_fn, log_exc_fn, log_error_fn):
ofport = self.agent._setup_tunnel_port(
- self.agent.tun_br, 'gre-1', 'remote_ip', p_const.TYPE_GRE)
+ self.agent.int_br, 'gre-1', 'remote_ip', p_const.TYPE_GRE)
add_tunnel_port_fn.assert_called_once_with(
'gre-1', 'remote_ip', self.agent.local_ip, p_const.TYPE_GRE,
self.agent.vxlan_udp_port, self.agent.dont_fragment)
self.agent.local_ip,
self.agent.tunnel_types[0])
- def test__provision_local_vlan_inbound_for_tunnel(self):
- with mock.patch.object(self.agent, 'ryu_send_msg') as sendmsg:
- self.agent._provision_local_vlan_inbound_for_tunnel(1, 'gre', 3)
-
- ofp = importutils.import_module('ryu.ofproto.ofproto_v1_3')
- ofpp = importutils.import_module('ryu.ofproto.ofproto_v1_3_parser')
- expected_msg = ofpp.OFPFlowMod(
- self.agent.tun_br.datapath,
- instructions=[
- ofpp.OFPInstructionActions(
- ofp.OFPIT_APPLY_ACTIONS,
- [
- ofpp.OFPActionPushVlan(),
- ofpp.OFPActionSetField(vlan_vid=1 |
- ofp.OFPVID_PRESENT),
- ]),
- ofpp.OFPInstructionGotoTable(
- table_id=constants.LEARN_FROM_TUN),
- ],
- match=ofpp.OFPMatch(tunnel_id=3),
- priority=1,
- table_id=constants.TUN_TABLE['gre'])
- sendmsg.assert_has_calls([mock.call(expected_msg)])
-
- def test__provision_local_vlan_outbound(self):
- with mock.patch.object(self.agent, 'ryu_send_msg') as sendmsg:
- self.agent._provision_local_vlan_outbound(888, 999, 'phys-net1')
-
- ofp = importutils.import_module('ryu.ofproto.ofproto_v1_3')
- ofpp = importutils.import_module('ryu.ofproto.ofproto_v1_3_parser')
- expected_msg = ofpp.OFPFlowMod(
- self.agent.phys_brs['phys-net1'].datapath,
- instructions=[
- ofpp.OFPInstructionActions(
- ofp.OFPIT_APPLY_ACTIONS,
- [
- ofpp.OFPActionSetField(vlan_vid=999),
- ofpp.OFPActionOutput(ofp.OFPP_NORMAL, 0),
- ]
- )
- ],
- match=ofpp.OFPMatch(
- in_port=777,
- vlan_vid=888 | ofp.OFPVID_PRESENT
- ),
- priority=4)
- sendmsg.assert_has_calls([mock.call(expected_msg)])
-
- def test__provision_local_vlan_inbound(self):
- with mock.patch.object(self.agent, 'ryu_send_msg') as sendmsg:
- self.agent._provision_local_vlan_inbound(888, 999, 'phys-net1')
-
- ofp = importutils.import_module('ryu.ofproto.ofproto_v1_3')
- ofpp = importutils.import_module('ryu.ofproto.ofproto_v1_3_parser')
- expected_msg = ofpp.OFPFlowMod(
- self.agent.int_br.datapath,
- instructions=[
- ofpp.OFPInstructionActions(
- ofp.OFPIT_APPLY_ACTIONS,
- [
- ofpp.OFPActionSetField(
- vlan_vid=888 | ofp.OFPVID_PRESENT
- ),
- ofpp.OFPActionOutput(ofp.OFPP_NORMAL, 0),
- ]
- )
- ],
- match=ofpp.OFPMatch(in_port=666, vlan_vid=999),
- priority=3)
- sendmsg.assert_has_calls([mock.call(expected_msg)])
-
- def test__reclaim_local_vlan_outbound(self):
- lvm = mock.Mock()
- lvm.network_type = p_const.TYPE_VLAN
- lvm.segmentation_id = 555
- lvm.vlan = 444
- lvm.physical_network = 'phys-net1'
- with mock.patch.object(self.agent, 'ryu_send_msg') as sendmsg:
- self.agent._reclaim_local_vlan_outbound(lvm)
-
- ofp = importutils.import_module('ryu.ofproto.ofproto_v1_3')
- ofpp = importutils.import_module('ryu.ofproto.ofproto_v1_3_parser')
- expected_msg = ofpp.OFPFlowMod(
- self.agent.phys_brs['phys-net1'].datapath,
- command=ofp.OFPFC_DELETE,
- match=ofpp.OFPMatch(
- in_port=777,
- vlan_vid=444 | ofp.OFPVID_PRESENT
- ),
- out_group=ofp.OFPG_ANY,
- out_port=ofp.OFPP_ANY,
- table_id=ofp.OFPTT_ALL)
- sendmsg.assert_has_calls([mock.call(expected_msg)])
-
- def test__reclaim_local_vlan_inbound(self):
- lvm = mock.Mock()
- lvm.network_type = p_const.TYPE_VLAN
- lvm.segmentation_id = 555
- lvm.vlan = 444
- lvm.physical_network = 'phys-net1'
- with mock.patch.object(self.agent, 'ryu_send_msg') as sendmsg:
- self.agent._reclaim_local_vlan_inbound(lvm)
-
- ofp = importutils.import_module('ryu.ofproto.ofproto_v1_3')
- ofpp = importutils.import_module('ryu.ofproto.ofproto_v1_3_parser')
- expected_msg = ofpp.OFPFlowMod(
- self.agent.int_br.datapath,
- command=ofp.OFPFC_DELETE,
- match=ofpp.OFPMatch(
- in_port=666,
- vlan_vid=555 | ofp.OFPVID_PRESENT
- ),
- out_group=ofp.OFPG_ANY,
- out_port=ofp.OFPP_ANY,
- table_id=ofp.OFPTT_ALL)
- sendmsg.assert_has_calls([mock.call(expected_msg)])
-
- def test__provision_local_vlan_outbound_flat(self):
- ofp = importutils.import_module('ryu.ofproto.ofproto_v1_3')
- ofpp = importutils.import_module('ryu.ofproto.ofproto_v1_3_parser')
- with mock.patch.object(self.agent, 'ryu_send_msg') as sendmsg:
- self.agent._provision_local_vlan_outbound(888, ofp.OFPVID_NONE,
- 'phys-net1')
-
- expected_msg = ofpp.OFPFlowMod(
- self.agent.phys_brs['phys-net1'].datapath,
- instructions=[
- ofpp.OFPInstructionActions(
- ofp.OFPIT_APPLY_ACTIONS,
- [
- ofpp.OFPActionPopVlan(),
- ofpp.OFPActionOutput(ofp.OFPP_NORMAL, 0),
- ]
- )
- ],
- match=ofpp.OFPMatch(
- in_port=777,
- vlan_vid=888 | ofp.OFPVID_PRESENT
- ),
- priority=4)
- sendmsg.assert_has_calls([mock.call(expected_msg)])
-
- def test__provision_local_vlan_inbound_flat(self):
- ofp = importutils.import_module('ryu.ofproto.ofproto_v1_3')
- ofpp = importutils.import_module('ryu.ofproto.ofproto_v1_3_parser')
- with mock.patch.object(self.agent, 'ryu_send_msg') as sendmsg:
- self.agent._provision_local_vlan_inbound(888, ofp.OFPVID_NONE,
- 'phys-net1')
-
- expected_msg = ofpp.OFPFlowMod(
- self.agent.int_br.datapath,
- instructions=[
- ofpp.OFPInstructionActions(
- ofp.OFPIT_APPLY_ACTIONS,
- [
- ofpp.OFPActionPushVlan(),
- ofpp.OFPActionSetField(
- vlan_vid=888 | ofp.OFPVID_PRESENT
- ),
- ofpp.OFPActionOutput(ofp.OFPP_NORMAL, 0),
- ]
- )
- ],
- match=ofpp.OFPMatch(in_port=666, vlan_vid=ofp.OFPVID_NONE),
- priority=3)
- sendmsg.assert_has_calls([mock.call(expected_msg)])
-
- def test__reclaim_local_vlan_outbound_flat(self):
- lvm = mock.Mock()
- lvm.network_type = p_const.TYPE_FLAT
- lvm.segmentation_id = 555
- lvm.vlan = 444
- lvm.physical_network = 'phys-net1'
- with mock.patch.object(self.agent, 'ryu_send_msg') as sendmsg:
- self.agent._reclaim_local_vlan_outbound(lvm)
-
- ofp = importutils.import_module('ryu.ofproto.ofproto_v1_3')
- ofpp = importutils.import_module('ryu.ofproto.ofproto_v1_3_parser')
- expected_msg = ofpp.OFPFlowMod(
- self.agent.phys_brs['phys-net1'].datapath,
- command=ofp.OFPFC_DELETE,
- match=ofpp.OFPMatch(
- in_port=777,
- vlan_vid=444 | ofp.OFPVID_PRESENT
- ),
- out_group=ofp.OFPG_ANY,
- out_port=ofp.OFPP_ANY,
- table_id=ofp.OFPTT_ALL)
- sendmsg.assert_has_calls([mock.call(expected_msg)])
-
- def test__reclaim_local_vlan_inbound_flat(self):
- lvm = mock.Mock()
- lvm.network_type = p_const.TYPE_FLAT
- lvm.segmentation_id = 555
- lvm.vlan = 444
- lvm.physical_network = 'phys-net1'
- with mock.patch.object(self.agent, 'ryu_send_msg') as sendmsg:
- self.agent._reclaim_local_vlan_inbound(lvm)
-
- ofp = importutils.import_module('ryu.ofproto.ofproto_v1_3')
- ofpp = importutils.import_module('ryu.ofproto.ofproto_v1_3_parser')
- expected_msg = ofpp.OFPFlowMod(
- self.agent.int_br.datapath,
- command=ofp.OFPFC_DELETE,
- match=ofpp.OFPMatch(
- in_port=666,
- vlan_vid=ofp.OFPVID_NONE
- ),
- out_group=ofp.OFPG_ANY,
- out_port=ofp.OFPP_ANY,
- table_id=ofp.OFPTT_ALL)
- sendmsg.assert_has_calls([mock.call(expected_msg)])
-
def test__get_ports(self):
ofpp = importutils.import_module('ryu.ofproto.ofproto_v1_3_parser')
reply = [ofpp.OFPPortDescStatsReply(body=[ofpp.OFPPort(name='hoge',
result = self.agent._get_ofport_names('hoge')
_get_ports.assert_called_once_with('hoge')
self.assertEqual(set(names), result)
-
- def test_setup_tunnel_br(self):
- 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.mod_agent, 'OVSBridge',
- return_value=self.agent.tun_br),
- mock.patch.object(self.agent,
- '_tun_br_output_arp_packet_to_controller')
- ) as (int_add_patch_port, tun_add_patch_port,
- ovs_br_class, tun_output_ctrl):
- self.agent.setup_tunnel_br(cfg.CONF.OVS.tunnel_bridge)
- tun_output_ctrl.assert_called_once_with(self.agent.tun_br)
--- /dev/null
+# Copyright (C) 2014 VA Linux Systems Japan K.K.
+# Copyright (C) 2014 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.openstack.common import importutils
+from neutron.tests.unit.ofagent import ofa_test_base
+
+
+class TestOFAgentFlows(ofa_test_base.OFATestBase):
+
+ _MOD = 'neutron.plugins.ofagent.agent.ofswitch'
+
+ def setUp(self):
+ super(TestOFAgentFlows, self).setUp()
+ self.mod = importutils.import_module(self._MOD)
+ self.br = self.mod.OpenFlowSwitch()
+ self.br.set_dp(self._mk_test_dp("dp"))
+
+ def test_delete_flows(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.delete_flows()
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, command=ofp.OFPFC_DELETE,
+ match=ofpp.OFPMatch(), out_group=ofp.OFPG_ANY,
+ out_port=ofp.OFPP_ANY, priority=0, table_id=ofp.OFPTT_ALL)),
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_install_default_drop(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.install_default_drop(table_id=98)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, priority=0, table_id=98)),
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_install_default_goto(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.install_default_goto(table_id=98, dest_table_id=150)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=150)],
+ priority=0, table_id=98)),
+ ]
+ sendmsg.assert_has_calls(expected_calls)
+
+ def test_install_default_goto_next(self):
+ br = self.br
+ with mock.patch.object(br, '_send_msg') as sendmsg:
+ br.install_default_goto_next(table_id=100)
+ (dp, ofp, ofpp) = br._get_dp()
+ call = mock.call
+ expected_calls = [
+ call(ofpp.OFPFlowMod(dp, instructions=[
+ ofpp.OFPInstructionGotoTable(table_id=101)],
+ priority=0, table_id=100)),
+ ]
+ sendmsg.assert_has_calls(expected_calls)