from neutron.common import utils as n_utils
from neutron.i18n import _LE, _LI, _LW
from neutron.openstack.common import log as logging
+from neutron.plugins.common import constants as p_const
from neutron.plugins.openvswitch.common import constants
-
LOG = logging.getLogger(__name__)
# 1.0 Initial version
def __init__(self, context, plugin_rpc, integ_br, tun_br,
+ bridge_mappings, phys_brs, int_ofports, phys_ofports,
patch_int_ofport=constants.OFPORT_INVALID,
patch_tun_ofport=constants.OFPORT_INVALID,
host=None, enable_tunneling=False,
self.host = host
self.enable_tunneling = enable_tunneling
self.enable_distributed_routing = enable_distributed_routing
+ self.bridge_mappings = bridge_mappings
+ self.phys_brs = phys_brs
+ self.int_ofports = int_ofports
+ self.phys_ofports = phys_ofports
self.reset_ovs_parameters(integ_br, tun_br,
patch_int_ofport, patch_tun_ofport)
self.reset_dvr_parameters()
self.dvr_mac_address = None
- if self.enable_tunneling and self.enable_distributed_routing:
+ if self.enable_distributed_routing:
self.get_dvr_mac_address()
def reset_ovs_parameters(self, integ_br, tun_br,
self.dvr_mac_address = details['mac_address']
return
- def setup_dvr_flows_on_integ_tun_br(self):
- '''Setup up initial dvr flows into br-int and br-tun'''
- if not (self.enable_tunneling and self.enable_distributed_routing):
- return
-
+ def setup_dvr_flows_on_integ_br(self):
+ '''Setup up initial dvr flows into br-int'''
if not self.in_distributed_mode():
return
priority=1,
actions="drop")
+ self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC_VLAN,
+ priority=1,
+ actions="drop")
+
# Insert 'normal' action as the default for Table LOCAL_SWITCHING
self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
priority=1,
actions="normal")
- dvr_macs = self.plugin_rpc.get_dvr_mac_address_list(self.context)
- LOG.debug("L2 Agent DVR: Received these MACs: %r", dvr_macs)
- for mac in dvr_macs:
- if mac['mac_address'] == self.dvr_mac_address:
- continue
- # Table 0 (default) will now sort DVR traffic from other
- # traffic depending on in_port
+ for physical_network in self.bridge_mappings:
self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
priority=2,
- in_port=self.patch_tun_ofport,
- dl_src=mac['mac_address'],
- actions="resubmit(,%s)" %
- constants.DVR_TO_SRC_MAC)
- # Table DVR_NOT_LEARN ensures unique dvr macs in the cloud
- # are not learnt, as they may
- # result in flow explosions
- self.tun_br.add_flow(table=constants.DVR_NOT_LEARN,
- priority=1,
- dl_src=mac['mac_address'],
- actions="output:%s" % self.patch_int_ofport)
+ in_port=self.int_ofports[physical_network],
+ actions="drop")
- self.registered_dvr_macs.add(mac['mac_address'])
+ def setup_dvr_flows_on_tun_br(self):
+ '''Setup up initial dvr flows into br-tun'''
+ if not self.enable_tunneling or not self.in_distributed_mode():
+ return
self.tun_br.add_flow(priority=1,
in_port=self.patch_int_ofport,
actions="resubmit(,%s)" %
constants.DVR_PROCESS)
+
# table-miss should be sent to learning table
self.tun_br.add_flow(table=constants.DVR_NOT_LEARN,
priority=0,
actions="resubmit(,%s)" %
constants.PATCH_LV_TO_TUN)
+ def setup_dvr_flows_on_phys_br(self):
+ '''Setup up initial dvr flows into br-phys'''
+ if not self.in_distributed_mode():
+ return
+
+ for physical_network in self.bridge_mappings:
+ self.phys_brs[physical_network].add_flow(priority=2,
+ in_port=self.phys_ofports[physical_network],
+ actions="resubmit(,%s)" %
+ constants.DVR_PROCESS_VLAN)
+ self.phys_brs[physical_network].add_flow(priority=1,
+ actions="resubmit(,%s)" %
+ constants.DVR_NOT_LEARN_VLAN)
+ self.phys_brs[physical_network].add_flow(
+ table=constants.DVR_PROCESS_VLAN,
+ priority=0,
+ actions="resubmit(,%s)" %
+ constants.LOCAL_VLAN_TRANSLATION)
+ self.phys_brs[physical_network].add_flow(
+ table=constants.LOCAL_VLAN_TRANSLATION,
+ priority=2,
+ in_port=self.phys_ofports[physical_network],
+ actions="drop")
+ self.phys_brs[physical_network].add_flow(
+ table=constants.DVR_NOT_LEARN_VLAN,
+ priority=1,
+ actions="NORMAL")
+
+ def setup_dvr_mac_flows_on_all_brs(self):
+ if not self.in_distributed_mode():
+ LOG.debug("Not in distributed mode, ignoring invocation "
+ "of get_dvr_mac_address_list() ")
+ return
+ dvr_macs = self.plugin_rpc.get_dvr_mac_address_list(self.context)
+ LOG.debug("L2 Agent DVR: Received these MACs: %r", dvr_macs)
+ for mac in dvr_macs:
+ if mac['mac_address'] == self.dvr_mac_address:
+ continue
+ for physical_network in self.bridge_mappings:
+ self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
+ priority=4,
+ in_port=self.int_ofports[physical_network],
+ dl_src=mac['mac_address'],
+ actions="resubmit(,%s)" %
+ constants.DVR_TO_SRC_MAC_VLAN)
+ self.phys_brs[physical_network].add_flow(
+ table=constants.DVR_NOT_LEARN_VLAN,
+ priority=2,
+ dl_src=mac,
+ actions="output:%s" %
+ self.phys_ofports[physical_network])
+
+ if self.enable_tunneling:
+ # Table 0 (default) will now sort DVR traffic from other
+ # traffic depending on in_port
+ self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
+ priority=2,
+ in_port=self.patch_tun_ofport,
+ dl_src=mac['mac_address'],
+ actions="resubmit(,%s)" %
+ constants.DVR_TO_SRC_MAC)
+ # Table DVR_NOT_LEARN ensures unique dvr macs in the cloud
+ # are not learnt, as they may
+ # result in flow explosions
+ self.tun_br.add_flow(table=constants.DVR_NOT_LEARN,
+ priority=1,
+ dl_src=mac,
+ actions="output:%s" %
+ self.patch_int_ofport)
+ self.registered_dvr_macs.add(mac['mac_address'])
+
def dvr_mac_address_update(self, dvr_macs):
if not self.dvr_mac_address:
LOG.debug("Self mac unknown, ignoring this "
dvr_macs_removed = self.registered_dvr_macs - dvr_host_macs
for oldmac in dvr_macs_removed:
- self.int_br.delete_flows(table=constants.LOCAL_SWITCHING,
- in_port=self.patch_tun_ofport,
- dl_src=oldmac)
- self.tun_br.delete_flows(table=constants.DVR_NOT_LEARN,
- dl_src=oldmac)
+ for physical_network in self.bridge_mappings:
+ self.int_br.delete_flows(table=constants.LOCAL_SWITCHING,
+ in_port=self.int_ofports[physical_network],
+ dl_src=oldmac)
+ self.phys_brs[physical_network].delete_flows(
+ table=constants.DVR_NOT_LEARN_VLAN,
+ dl_src=oldmac)
+ if self.enable_tunneling:
+ self.int_br.delete_flows(table=constants.LOCAL_SWITCHING,
+ in_port=self.patch_tun_ofport,
+ dl_src=oldmac)
+ self.tun_br.delete_flows(table=constants.DVR_NOT_LEARN,
+ dl_src=oldmac)
LOG.debug("Removed DVR MAC flow for %s", oldmac)
self.registered_dvr_macs.remove(oldmac)
for newmac in dvr_macs_added:
- self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
- priority=2,
- in_port=self.patch_tun_ofport,
- dl_src=newmac,
- actions="resubmit(,%s)" %
- constants.DVR_TO_SRC_MAC)
- self.tun_br.add_flow(table=constants.DVR_NOT_LEARN,
- priority=1,
- dl_src=newmac,
- actions="output:%s" % self.patch_int_ofport)
+ for physical_network in self.bridge_mappings:
+ self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
+ priority=4,
+ in_port=self.int_ofports[physical_network],
+ dl_src=newmac,
+ actions="resubmit(,%s)" %
+ constants.DVR_TO_SRC_MAC_VLAN)
+ self.phys_brs[physical_network].add_flow(
+ table=constants.DVR_NOT_LEARN_VLAN,
+ priority=2,
+ dl_src=newmac,
+ actions="output:%s" %
+ self.phys_ofports[physical_network])
+ if self.enable_tunneling:
+ self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
+ priority=2,
+ in_port=self.patch_tun_ofport,
+ dl_src=newmac,
+ actions="resubmit(,%s)" %
+ constants.DVR_TO_SRC_MAC)
+ self.tun_br.add_flow(table=constants.DVR_NOT_LEARN,
+ priority=1,
+ dl_src=newmac,
+ actions="output:%s" %
+ self.patch_int_ofport)
LOG.debug("Added DVR MAC flow for %s", newmac)
self.registered_dvr_macs.add(newmac)
return device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE
def process_tunneled_network(self, network_type, lvid, segmentation_id):
- if not (self.enable_tunneling and self.enable_distributed_routing):
- return
-
if self.in_distributed_mode():
table_id = constants.DVR_NOT_LEARN
else:
"resubmit(,%s)" %
(lvid, table_id))
- def _bind_distributed_router_interface_port(self, port, fixed_ips,
- device_owner, local_vlan):
+ def _bind_distributed_router_interface_port(self, port, lvm,
+ fixed_ips, device_owner):
# since router port must have only one fixed IP, directly
# use fixed_ips[0]
subnet_uuid = fixed_ips[0]['subnet_id']
# DVR takes over
ldm.set_dvr_owned(True)
+ table_id = constants.DVR_TO_SRC_MAC
+ vlan_to_use = lvm.vlan
+ if lvm.network_type == p_const.TYPE_VLAN:
+ table_id = constants.DVR_TO_SRC_MAC_VLAN
+ vlan_to_use = lvm.segmentation_id
+
subnet_info = ldm.get_subnet_info()
- ip_subnet = subnet_info['cidr']
+ ip_version = subnet_info['ip_version']
local_compute_ports = (
self.plugin_rpc.get_ports_on_host_by_subnet(
self.context, self.host, subnet_uuid))
# ensure if a compute port is already on
# a different dvr routed subnet
# if yes, queue this subnet to that port
- ovsport = self.local_ports[vif.vif_id]
- ovsport.add_subnet(subnet_uuid)
+ comp_ovsport = self.local_ports[vif.vif_id]
+ comp_ovsport.add_subnet(subnet_uuid)
else:
# the compute port is discovered first here that its on
# a dvr routed subnet queue this subnet to that port
- ovsport = OVSPort(vif.vif_id, vif.ofport,
+ comp_ovsport = OVSPort(vif.vif_id, vif.ofport,
vif.vif_mac, prt['device_owner'])
-
- ovsport.add_subnet(subnet_uuid)
- self.local_ports[vif.vif_id] = ovsport
-
+ comp_ovsport.add_subnet(subnet_uuid)
+ self.local_ports[vif.vif_id] = comp_ovsport
# create rule for just this vm port
- self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC,
+ self.int_br.add_flow(table=table_id,
priority=4,
- dl_vlan=local_vlan,
- dl_dst=ovsport.get_mac(),
+ dl_vlan=vlan_to_use,
+ dl_dst=comp_ovsport.get_mac(),
actions="strip_vlan,mod_dl_src:%s,"
"output:%s" %
(subnet_info['gateway_mac'],
- ovsport.get_ofport()))
-
- # create rule to forward broadcast/multicast frames from dvr
- # router interface to appropriate local tenant ports
- ofports = ','.join(map(str, ldm.get_compute_ofports().values()))
- if csnat_ofport != constants.OFPORT_INVALID:
- ofports = str(csnat_ofport) + ',' + ofports
- ip_version = subnet_info['ip_version']
- if ofports:
- args = self._get_flow_args_by_version(
- ip_version, constants.DVR_TO_SRC_MAC, local_vlan, ip_subnet,
- 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
- (subnet_info['gateway_mac'], ofports)))
- self.int_br.add_flow(**args)
-
- args = {'table': constants.DVR_PROCESS,
- 'priority': 3,
- 'dl_vlan': local_vlan,
- 'actions': "drop"}
- if ip_version == 4:
- args['proto'] = 'arp'
- args['nw_dst'] = subnet_info['gateway_ip']
- else:
- args['proto'] = 'icmp6'
- args['icmp_type'] = n_const.ICMPV6_TYPE_RA
- args['dl_src'] = subnet_info['gateway_mac']
-
- self.tun_br.add_flow(**args)
- self.tun_br.add_flow(table=constants.DVR_PROCESS,
- priority=2,
- dl_vlan=local_vlan,
- dl_dst=port.vif_mac,
- actions="drop")
+ comp_ovsport.get_ofport()))
- self.tun_br.add_flow(table=constants.DVR_PROCESS,
- priority=1,
- dl_vlan=local_vlan,
- dl_src=port.vif_mac,
- actions="mod_dl_src:%s,resubmit(,%s)" %
- (self.dvr_mac_address,
- constants.PATCH_LV_TO_TUN))
+ if lvm.network_type == p_const.TYPE_VLAN:
+ args = {'table': constants.DVR_PROCESS_VLAN,
+ 'priority': 3,
+ 'dl_vlan': lvm.vlan,
+ 'actions': "drop"}
+ if ip_version == 4:
+ args['proto'] = 'arp'
+ args['nw_dst'] = subnet_info['gateway_ip']
+ else:
+ args['proto'] = 'icmp6'
+ args['icmp_type'] = n_const.ICMPV6_TYPE_RA
+ args['dl_src'] = subnet_info['gateway_mac']
+ # TODO(vivek) remove the IPv6 related add_flow once SNAT is not
+ # used for IPv6 DVR.
+ self.phys_brs[lvm.physical_network].add_flow(**args)
+ self.phys_brs[lvm.physical_network].add_flow(
+ table=constants.DVR_PROCESS_VLAN,
+ priority=2,
+ dl_vlan=lvm.vlan,
+ dl_dst=port.vif_mac,
+ actions="drop")
+
+ self.phys_brs[lvm.physical_network].add_flow(
+ table=constants.DVR_PROCESS_VLAN,
+ priority=1,
+ dl_vlan=lvm.vlan,
+ dl_src=port.vif_mac,
+ actions="mod_dl_src:%s,resubmit(,%s)" %
+ (self.dvr_mac_address, constants.LOCAL_VLAN_TRANSLATION))
+
+ if lvm.network_type in constants.TUNNEL_NETWORK_TYPES:
+ args = {'table': constants.DVR_PROCESS,
+ 'priority': 3,
+ 'dl_vlan': lvm.vlan,
+ 'actions': "drop"}
+ if ip_version == 4:
+ args['proto'] = 'arp'
+ args['nw_dst'] = subnet_info['gateway_ip']
+ else:
+ args['proto'] = 'icmp6'
+ args['icmp_type'] = n_const.ICMPV6_TYPE_RA
+ args['dl_src'] = subnet_info['gateway_mac']
+ # TODO(vivek) remove the IPv6 related add_flow once SNAT is not
+ # used for IPv6 DVR.
+ self.tun_br.add_flow(**args)
+ self.tun_br.add_flow(table=constants.DVR_PROCESS,
+ priority=2,
+ dl_vlan=lvm.vlan,
+ dl_dst=port.vif_mac,
+ actions="drop")
+ self.tun_br.add_flow(table=constants.DVR_PROCESS,
+ priority=1,
+ dl_vlan=lvm.vlan,
+ dl_src=port.vif_mac,
+ actions="mod_dl_src:%s,resubmit(,%s)" %
+ (self.dvr_mac_address,
+ constants.PATCH_LV_TO_TUN))
# the dvr router interface is itself a port, so capture it
# queue this subnet to that port. A subnet appears only once as
# a router interface on any given router
ovsport.add_subnet(subnet_uuid)
self.local_ports[port.vif_id] = ovsport
- def _bind_port_on_dvr_subnet(self, port, fixed_ips,
- device_owner, local_vlan):
+ def _bind_port_on_dvr_subnet(self, port, lvm, fixed_ips,
+ device_owner):
# Handle new compute port added use-case
subnet_uuid = None
for ips in fixed_ips:
# the integration bridge
LOG.debug("DVR: Plumbing compute port %s", port.vif_id)
subnet_info = ldm.get_subnet_info()
- ip_subnet = subnet_info['cidr']
- csnat_ofport = ldm.get_csnat_ofport()
ldm.add_compute_ofport(port.vif_id, port.ofport)
if port.vif_id in self.local_ports:
# ensure if a compute port is already on a different
# on a dvr routed subnet, queue this subnet to that port
ovsport = OVSPort(port.vif_id, port.ofport,
port.vif_mac, device_owner)
-
ovsport.add_subnet(subnet_uuid)
self.local_ports[port.vif_id] = ovsport
+ table_id = constants.DVR_TO_SRC_MAC
+ vlan_to_use = lvm.vlan
+ if lvm.network_type == p_const.TYPE_VLAN:
+ table_id = constants.DVR_TO_SRC_MAC_VLAN
+ vlan_to_use = lvm.segmentation_id
# create a rule for this vm port
- self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC,
+ self.int_br.add_flow(table=table_id,
priority=4,
- dl_vlan=local_vlan,
+ dl_vlan=vlan_to_use,
dl_dst=ovsport.get_mac(),
actions="strip_vlan,mod_dl_src:%s,"
"output:%s" %
(subnet_info['gateway_mac'],
ovsport.get_ofport()))
- ofports = ','.join(map(str, ldm.get_compute_ofports().values()))
- if csnat_ofport != constants.OFPORT_INVALID:
- ofports = str(csnat_ofport) + ',' + ofports
- ip_version = subnet_info['ip_version']
- args = self._get_flow_args_by_version(
- ip_version, constants.DVR_TO_SRC_MAC, local_vlan, ip_subnet,
- 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
- (subnet_info['gateway_mac'], ofports)))
- self.int_br.add_flow(**args)
-
- def _bind_centralized_snat_port_on_dvr_subnet(self, port, fixed_ips,
- device_owner, local_vlan):
+ def _bind_centralized_snat_port_on_dvr_subnet(self, port, lvm,
+ fixed_ips, device_owner):
if port.vif_id in self.local_ports:
# throw an error if CSNAT port is already on a different
# dvr routed subnet
port.vif_mac, device_owner)
ovsport.add_subnet(subnet_uuid)
self.local_ports[port.vif_id] = ovsport
-
- self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC,
+ table_id = constants.DVR_TO_SRC_MAC
+ vlan_to_use = lvm.vlan
+ if lvm.network_type == p_const.TYPE_VLAN:
+ table_id = constants.DVR_TO_SRC_MAC_VLAN
+ vlan_to_use = lvm.segmentation_id
+ self.int_br.add_flow(table=table_id,
priority=4,
- dl_vlan=local_vlan,
+ dl_vlan=vlan_to_use,
dl_dst=ovsport.get_mac(),
actions="strip_vlan,mod_dl_src:%s,"
" output:%s" %
(subnet_info['gateway_mac'],
ovsport.get_ofport()))
- ofports = ','.join(map(str, ldm.get_compute_ofports().values()))
- ofports = str(ldm.get_csnat_ofport()) + ',' + ofports
- ip_subnet = subnet_info['cidr']
- # TODO(xuhanp) remove the IPv6 related add_flow once SNAT is not
- # used for IPv6 DVR.
- ip_version = subnet_info['ip_version']
- args = self._get_flow_args_by_version(
- ip_version, constants.DVR_TO_SRC_MAC, local_vlan, ip_subnet,
- 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
- (subnet_info['gateway_mac'], ofports)))
- self.int_br.add_flow(**args)
-
- def bind_port_to_dvr(self, port, network_type, fixed_ips,
- device_owner, local_vlan_id):
+ def bind_port_to_dvr(self, port, local_vlan_map,
+ fixed_ips, device_owner):
if not self.in_distributed_mode():
return
- if network_type not in constants.TUNNEL_NETWORK_TYPES:
+ if local_vlan_map.network_type not in (constants.TUNNEL_NETWORK_TYPES
+ + [p_const.TYPE_VLAN]):
+ LOG.debug("DVR: Port %s is with network_type %s not supported"
+ " for dvr plumbing" % (port.vif_id,
+ local_vlan_map.network_type))
return
if device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE:
- self._bind_distributed_router_interface_port(port, fixed_ips,
- device_owner,
- local_vlan_id)
+ self._bind_distributed_router_interface_port(port,
+ local_vlan_map,
+ fixed_ips,
+ device_owner)
if device_owner and n_utils.is_dvr_serviced(device_owner):
- self._bind_port_on_dvr_subnet(port, fixed_ips,
- device_owner,
- local_vlan_id)
+ self._bind_port_on_dvr_subnet(port, local_vlan_map,
+ fixed_ips,
+ device_owner)
if device_owner == n_const.DEVICE_OWNER_ROUTER_SNAT:
- self._bind_centralized_snat_port_on_dvr_subnet(port, fixed_ips,
- device_owner,
- local_vlan_id)
-
- def _unbind_distributed_router_interface_port(self, port, local_vlan):
+ self._bind_centralized_snat_port_on_dvr_subnet(port,
+ local_vlan_map,
+ fixed_ips,
+ device_owner)
+ def _unbind_distributed_router_interface_port(self, port, lvm):
ovsport = self.local_ports[port.vif_id]
-
# removal of distributed router interface
subnet_ids = ovsport.get_subnets()
subnet_set = set(subnet_ids)
+ network_type = lvm.network_type
+ physical_network = lvm.physical_network
+ table_id = constants.DVR_TO_SRC_MAC
+ vlan_to_use = lvm.vlan
+ if network_type == p_const.TYPE_VLAN:
+ table_id = constants.DVR_TO_SRC_MAC_VLAN
+ vlan_to_use = lvm.segmentation_id
# ensure we process for all the subnets laid on this removed port
for sub_uuid in subnet_set:
if sub_uuid not in self.local_dvr_map:
continue
-
ldm = self.local_dvr_map[sub_uuid]
subnet_info = ldm.get_subnet_info()
- ip_subnet = subnet_info['cidr']
-
+ ip_version = subnet_info['ip_version']
# DVR is no more owner
ldm.set_dvr_owned(False)
-
# remove all vm rules for this dvr subnet
# clear of compute_ports altogether
compute_ports = ldm.get_compute_ofports()
for vif_id in compute_ports:
- ovsport = self.local_ports[vif_id]
- self.int_br.delete_flows(table=constants.DVR_TO_SRC_MAC,
- dl_vlan=local_vlan,
- dl_dst=ovsport.get_mac())
+ comp_port = self.local_ports[vif_id]
+ self.int_br.delete_flows(table=table_id,
+ dl_vlan=vlan_to_use,
+ dl_dst=comp_port.get_mac())
ldm.remove_all_compute_ofports()
- ip_version = subnet_info['ip_version']
- if ldm.get_csnat_ofport() != -1:
- # If there is a csnat port on this agent, preserve
- # the local_dvr_map state
- ofports = str(ldm.get_csnat_ofport())
- args = self._get_flow_args_by_version(
- ip_version, constants.DVR_TO_SRC_MAC,
- local_vlan, ip_subnet,
- 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
- (subnet_info['gateway_mac'], ofports)))
- self.int_br.add_flow(**args)
- else:
- # removed port is a distributed router interface
- args = self._get_flow_args_by_version(
- ip_version, constants.DVR_TO_SRC_MAC,
- local_vlan, ip_subnet, None, None)
- self.int_br.delete_flows(**args)
- # remove subnet from local_dvr_map as no dvr (or) csnat
+ if ldm.get_csnat_ofport() == constants.OFPORT_INVALID:
+ # if there is no csnat port for this subnet, remove
+ # this subnet from local_dvr_map, as no dvr (or) csnat
# ports available on this agent anymore
self.local_dvr_map.pop(sub_uuid, None)
-
- args = {'table': constants.DVR_PROCESS,
- 'dl_vlan': local_vlan}
- if ip_version == 4:
- args['proto'] = 'arp'
- args['nw_dst'] = subnet_info['gateway_ip']
- else:
- args['proto'] = 'icmp6'
- args['icmp_type'] = n_const.ICMPV6_TYPE_RA
- args['dl_src'] = subnet_info['gateway_mac']
-
- self.tun_br.delete_flows(**args)
+ if network_type == p_const.TYPE_VLAN:
+ args = {'table': constants.DVR_PROCESS_VLAN,
+ 'dl_vlan': lvm.vlan}
+ if ip_version == 4:
+ args['proto'] = 'arp'
+ args['nw_dst'] = subnet_info['gateway_ip']
+ else:
+ args['proto'] = 'icmp6'
+ args['icmp_type'] = n_const.ICMPV6_TYPE_RA
+ args['dl_src'] = subnet_info['gateway_mac']
+ self.phys_br[physical_network].delete_flows(**args)
+
+ if network_type in constants.TUNNEL_NETWORK_TYPES:
+ args = {'table': constants.DVR_PROCESS,
+ 'dl_vlan': lvm.vlan}
+ if ip_version == 4:
+ args['proto'] = 'arp'
+ args['nw_dst'] = subnet_info['gateway_ip']
+ else:
+ args['proto'] = 'icmp6'
+ args['icmp_type'] = n_const.ICMPV6_TYPE_RA
+ args['dl_src'] = subnet_info['gateway_mac']
+ self.tun_br.delete_flows(**args)
ovsport.remove_subnet(sub_uuid)
- self.tun_br.delete_flows(table=constants.DVR_PROCESS,
- dl_vlan=local_vlan,
- dl_dst=port.vif_mac)
-
- self.tun_br.delete_flows(table=constants.DVR_PROCESS,
- dl_vlan=local_vlan,
- dl_src=port.vif_mac)
+ if lvm.network_type == p_const.TYPE_VLAN:
+ self.phys_br[physical_network].delete_flows(
+ table=constants.DVR_PROCESS_VLAN,
+ dl_vlan=lvm.vlan,
+ dl_dst=port.vif_mac)
+ self.phys_br[physical_network].delete_flows(
+ table=constants.DVR_PROCESS_VLAN,
+ dl_vlan=lvm.vlan,
+ dl_src=port.vif_mac)
+
+ if lvm.network_type in constants.TUNNEL_NETWORK_TYPES:
+ self.tun_br.delete_flows(table=constants.DVR_PROCESS,
+ dl_vlan=lvm.vlan,
+ dl_dst=port.vif_mac)
+ self.tun_br.delete_flows(table=constants.DVR_PROCESS,
+ dl_vlan=lvm.vlan,
+ dl_src=port.vif_mac)
# release port state
self.local_ports.pop(port.vif_id, None)
- def _unbind_port_on_dvr_subnet(self, port, local_vlan):
-
+ def _unbind_port_on_dvr_subnet(self, port, lvm):
ovsport = self.local_ports[port.vif_id]
# This confirms that this compute port being removed belonged
# to a dvr hosted subnet.
- # Accommodate this VM Port into the existing rule in
- # the integration bridge
LOG.debug("DVR: Removing plumbing for compute port %s", port)
subnet_ids = ovsport.get_subnets()
# ensure we process for all the subnets laid on this port
for sub_uuid in subnet_ids:
if sub_uuid not in self.local_dvr_map:
continue
-
ldm = self.local_dvr_map[sub_uuid]
- subnet_info = ldm.get_subnet_info()
ldm.remove_compute_ofport(port.vif_id)
- ofports = ','.join(map(str, ldm.get_compute_ofports().values()))
- ip_subnet = subnet_info['cidr']
- ip_version = subnet_info['ip_version']
+ table_id = constants.DVR_TO_SRC_MAC
+ vlan_to_use = lvm.vlan
+ if lvm.network_type == p_const.TYPE_VLAN:
+ table_id = constants.DVR_TO_SRC_MAC_VLAN
+ vlan_to_use = lvm.segmentation_id
# first remove this vm port rule
- self.int_br.delete_flows(table=constants.DVR_TO_SRC_MAC,
- dl_vlan=local_vlan,
+ self.int_br.delete_flows(table=table_id,
+ dl_vlan=vlan_to_use,
dl_dst=ovsport.get_mac())
- if ldm.get_csnat_ofport() != -1:
- # If there is a csnat port on this agent, preserve
- # the local_dvr_map state
- ofports = str(ldm.get_csnat_ofport()) + ',' + ofports
- args = self._get_flow_args_by_version(
- ip_version, constants.DVR_TO_SRC_MAC,
- local_vlan, ip_subnet,
- 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
- (subnet_info['gateway_mac'], ofports)))
- self.int_br.add_flow(**args)
- else:
- if ofports:
- args = self._get_flow_args_by_version(
- ip_version, constants.DVR_TO_SRC_MAC,
- local_vlan, ip_subnet,
- 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
- (subnet_info['gateway_mac'], ofports)))
- self.int_br.add_flow(**args)
- else:
- # remove the flow altogether, as no ports (both csnat/
- # compute) are available on this subnet in this
- # agent
- args = self._get_flow_args_by_version(
- ip_version, constants.DVR_TO_SRC_MAC,
- local_vlan, ip_subnet, None, None)
- self.int_br.delete_flows(**args)
-
# release port state
self.local_ports.pop(port.vif_id, None)
- def _unbind_centralized_snat_port_on_dvr_subnet(self, port, local_vlan):
-
+ def _unbind_centralized_snat_port_on_dvr_subnet(self, port, lvm):
ovsport = self.local_ports[port.vif_id]
# This confirms that this compute port being removed belonged
# to a dvr hosted subnet.
- # Accommodate this VM Port into the existing rule in
- # the integration bridge
LOG.debug("DVR: Removing plumbing for csnat port %s", port)
sub_uuid = list(ovsport.get_subnets())[0]
# ensure we process for all the subnets laid on this port
if sub_uuid not in self.local_dvr_map:
return
ldm = self.local_dvr_map[sub_uuid]
- subnet_info = ldm.get_subnet_info()
- ip_subnet = subnet_info['cidr']
ldm.set_csnat_ofport(constants.OFPORT_INVALID)
+ table_id = constants.DVR_TO_SRC_MAC
+ vlan_to_use = lvm.vlan
+ if lvm.network_type == p_const.TYPE_VLAN:
+ table_id = constants.DVR_TO_SRC_MAC_VLAN
+ vlan_to_use = lvm.segmentation_id
# then remove csnat port rule
- self.int_br.delete_flows(table=constants.DVR_TO_SRC_MAC,
- dl_vlan=local_vlan,
+ self.int_br.delete_flows(table=table_id,
+ dl_vlan=vlan_to_use,
dl_dst=ovsport.get_mac())
- ofports = ','.join(map(str, ldm.get_compute_ofports().values()))
- ip_version = subnet_info['ip_version']
- if ofports:
- # TODO(xuhanp) remove the IPv6 related add_flow once SNAT is not
- # used for IPv6 DVR.
- args = self._get_flow_args_by_version(
- ip_version, constants.DVR_TO_SRC_MAC,
- local_vlan, ip_subnet,
- 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
- (subnet_info['gateway_mac'], ofports)))
- self.int_br.add_flow(**args)
- else:
- args = self._get_flow_args_by_version(
- ip_version, constants.DVR_TO_SRC_MAC,
- local_vlan, ip_subnet, None, None)
- self.int_br.delete_flows(**args)
-
if not ldm.is_dvr_owned():
# if not owned by DVR (only used for csnat), remove this
# subnet state altogether
self.local_dvr_map.pop(sub_uuid, None)
-
# release port state
self.local_ports.pop(port.vif_id, None)
args['actions'] = actions
return args
- def unbind_port_from_dvr(self, vif_port, local_vlan_id):
+ def unbind_port_from_dvr(self, vif_port, local_vlan_map):
if not self.in_distributed_mode():
return
# Handle port removed use-case
if device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE:
self._unbind_distributed_router_interface_port(vif_port,
- local_vlan_id)
+ local_vlan_map)
if device_owner and n_utils.is_dvr_serviced(device_owner):
- self._unbind_port_on_dvr_subnet(vif_port, local_vlan_id)
+ self._unbind_port_on_dvr_subnet(vif_port,
+ local_vlan_map)
if device_owner == n_const.DEVICE_OWNER_ROUTER_SNAT:
self._unbind_centralized_snat_port_on_dvr_subnet(vif_port,
- local_vlan_id)
+ local_vlan_map)
self.dvr_plugin_rpc,
self.int_br,
self.tun_br,
+ self.bridge_mappings,
+ self.phys_brs,
+ self.int_ofports,
+ self.phys_ofports,
self.patch_int_ofport,
self.patch_tun_ofport,
cfg.CONF.host,
if self.enable_tunneling:
self.setup_tunnel_br()
- self.dvr_agent.setup_dvr_flows_on_integ_tun_br()
+ self.dvr_agent.setup_dvr_flows_on_integ_br()
+ self.dvr_agent.setup_dvr_flows_on_tun_br()
+ self.dvr_agent.setup_dvr_flows_on_phys_br()
+ self.dvr_agent.setup_dvr_mac_flows_on_all_brs()
# Collect additional bridges to monitor
self.ancillary_brs = self.setup_ancillary_bridges(integ_br, tun_br)
if physical_network in self.phys_brs:
# outbound
br = self.phys_brs[physical_network]
- br.add_flow(priority=4,
+ if self.enable_distributed_routing:
+ br.add_flow(table=constants.LOCAL_VLAN_TRANSLATION,
+ priority=4,
in_port=self.phys_ofports[physical_network],
dl_vlan=lvid,
actions="mod_vlan_vid:%s,normal" % segmentation_id)
+ else:
+ br.add_flow(priority=4,
+ in_port=self.phys_ofports[physical_network],
+ dl_vlan=lvid,
+ actions="mod_vlan_vid:%s,normal" % segmentation_id)
+
# inbound
self.int_br.add_flow(priority=3,
in_port=self.
lvm = self.local_vlan_map[net_uuid]
lvm.vif_ports[port.vif_id] = port
- self.dvr_agent.bind_port_to_dvr(port, network_type, fixed_ips,
- device_owner,
- local_vlan_id=lvm.vlan)
+ self.dvr_agent.bind_port_to_dvr(port, lvm,
+ fixed_ips,
+ device_owner)
# Do not bind a port if it's already bound
cur_tag = self.int_br.db_get_val("Port", port.port_name, "tag")
if vif_id in lvm.vif_ports:
vif_port = lvm.vif_ports[vif_id]
- self.dvr_agent.unbind_port_from_dvr(vif_port,
- local_vlan_id=lvm.vlan)
+ self.dvr_agent.unbind_port_from_dvr(vif_port, lvm)
lvm.vif_ports.pop(vif_id, None)
if not lvm.vif_ports:
# Various tables for DVR use of integration bridge flows
LOCAL_SWITCHING = 0
DVR_TO_SRC_MAC = 1
+DVR_TO_SRC_MAC_VLAN = 2
# Various tables for tunneling flows
DVR_PROCESS = 1
ARP_RESPONDER = 21
FLOOD_TO_TUN = 22
+# Various tables for DVR use of physical bridge flows
+DVR_PROCESS_VLAN = 1
+LOCAL_VLAN_TRANSLATION = 2
+DVR_NOT_LEARN_VLAN = 3
+
# Tables for integration bridge
# Table 0 is used for forwarding.
CANARY_TABLE = 23
--- /dev/null
+# Copyright (c) 2012 OpenStack Foundation.
+#
+# 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 contextlib
+
+import mock
+from oslo.config import cfg
+from oslo import messaging
+
+from neutron.agent.linux import utils
+from neutron.common import constants as n_const
+from neutron.plugins.common import constants as p_const
+from neutron.plugins.openvswitch.agent import ovs_neutron_agent
+from neutron.plugins.openvswitch.common import constants
+from neutron.tests import base
+
+
+NOTIFIER = 'neutron.plugins.ml2.rpc.AgentNotifierApi'
+OVS_LINUX_KERN_VERS_WITHOUT_VXLAN = "3.12.0"
+
+FAKE_MAC = '00:11:22:33:44:55'
+FAKE_IP1 = '10.0.0.1'
+FAKE_IP2 = '10.0.0.2'
+
+
+class CreateAgentConfigMapDvr(base.BaseTestCase):
+
+ def test_create_agent_config_map_enable_distributed_routing(self):
+ self.addCleanup(cfg.CONF.reset)
+ # Verify setting only enable_tunneling will default tunnel_type to GRE
+ cfg.CONF.set_override('enable_distributed_routing', True,
+ group='AGENT')
+ cfgmap = ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ self.assertEqual(cfgmap['enable_distributed_routing'], True)
+
+
+class TestOvsDvrNeutronAgent(base.BaseTestCase):
+
+ def setUp(self):
+ super(TestOvsDvrNeutronAgent, self).setUp()
+ notifier_p = mock.patch(NOTIFIER)
+ notifier_cls = notifier_p.start()
+ self.notifier = mock.Mock()
+ notifier_cls.return_value = self.notifier
+ cfg.CONF.set_default('firewall_driver',
+ 'neutron.agent.firewall.NoopFirewallDriver',
+ group='SECURITYGROUP')
+ kwargs = ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+
+ class MockFixedIntervalLoopingCall(object):
+ def __init__(self, f):
+ self.f = f
+
+ def start(self, interval=0):
+ self.f()
+
+ with contextlib.nested(
+ mock.patch('neutron.plugins.openvswitch.agent.ovs_neutron_agent.'
+ 'OVSNeutronAgent.setup_integration_br',
+ return_value=mock.Mock()),
+ mock.patch('neutron.plugins.openvswitch.agent.ovs_neutron_agent.'
+ 'OVSNeutronAgent.setup_ancillary_bridges',
+ return_value=[]),
+ mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'create'),
+ mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'set_secure_mode'),
+ mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'get_local_port_mac',
+ return_value='00:00:00:00:00:01'),
+ mock.patch('neutron.agent.linux.utils.get_interface_mac',
+ return_value='00:00:00:00:00:01'),
+ mock.patch('neutron.agent.linux.ovs_lib.BaseOVS.get_bridges'),
+ mock.patch('neutron.openstack.common.loopingcall.'
+ 'FixedIntervalLoopingCall',
+ new=MockFixedIntervalLoopingCall)):
+ self.agent = ovs_neutron_agent.OVSNeutronAgent(**kwargs)
+ # set back to true because initial report state will succeed due
+ # to mocked out RPC calls
+ self.agent.use_call = True
+ self.agent.tun_br = mock.Mock()
+ self.agent.sg_agent = mock.Mock()
+
+ def _setup_for_dvr_test(self, ofport=10):
+ self._port = mock.Mock()
+ self._port.ofport = ofport
+ self._port.vif_id = "1234-5678-90"
+ self._physical_network = 'physeth1'
+ self._old_local_vlan = None
+ self._segmentation_id = 2001
+ self.agent.enable_distributed_routing = True
+ self.agent.enable_tunneling = True
+ self.agent.patch_tun_ofport = 1
+ self.agent.patch_int_ofport = 2
+ self.agent.dvr_agent.local_ports = {}
+ self.agent.local_vlan_map = {}
+ self.agent.dvr_agent.enable_distributed_routing = True
+ self.agent.dvr_agent.enable_tunneling = True
+ self.agent.dvr_agent.patch_tun_ofport = 1
+ self.agent.dvr_agent.patch_int_ofport = 2
+ self.agent.dvr_agent.tun_br = mock.Mock()
+ self.agent.dvr_agent.phys_brs[self._physical_network] = mock.Mock()
+ self.agent.dvr_agent.bridge_mappings = {self._physical_network:
+ 'br-eth1'}
+ self.agent.dvr_agent.int_ofports[self._physical_network] = 30
+ self.agent.dvr_agent.phys_ofports[self._physical_network] = 40
+ self.agent.dvr_agent.local_dvr_map = {}
+ self.agent.dvr_agent.registered_dvr_macs = set()
+ self.agent.dvr_agent.dvr_mac_address = 'aa:22:33:44:55:66'
+ self._net_uuid = 'my-net-uuid'
+ self._fixed_ips = [{'subnet_id': 'my-subnet-uuid',
+ 'ip_address': '1.1.1.1'}]
+ self._compute_port = mock.Mock()
+ self._compute_port.ofport = 20
+ self._compute_port.vif_id = "1234-5678-91"
+ self._compute_fixed_ips = [{'subnet_id': 'my-subnet-uuid',
+ 'ip_address': '1.1.1.3'}]
+
+ def _test_port_bound_for_dvr_on_vlan_network(self, device_owner,
+ ip_version=4):
+ self._setup_for_dvr_test()
+ if ip_version == 4:
+ gateway_ip = '1.1.1.1'
+ cidr = '1.1.1.0/24'
+ else:
+ gateway_ip = '2001:100::1'
+ cidr = '2001:100::0/64'
+ self._port.vif_mac = gateway_mac = 'aa:bb:cc:11:22:33'
+ self._compute_port.vif_mac = '77:88:99:00:11:22'
+ physical_network = self._physical_network
+ segmentation_id = self._segmentation_id
+ network_type = p_const.TYPE_VLAN
+ with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'set_db_attribute',
+ return_value=True):
+ with contextlib.nested(
+ mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'db_get_val',
+ return_value=str(self._old_local_vlan)),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_subnet_for_dvr',
+ return_value={
+ 'gateway_ip': gateway_ip,
+ 'cidr': cidr,
+ 'ip_version': ip_version,
+ 'gateway_mac': gateway_mac}),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_ports_on_host_by_subnet',
+ return_value=[]),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'get_vif_port_by_id',
+ return_value=self._port),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows'),
+ mock.patch.object(
+ self.agent.dvr_agent.phys_brs[physical_network],
+ 'add_flow'),
+ mock.patch.object(
+ self.agent.dvr_agent.phys_brs[physical_network],
+ 'delete_flows')
+ ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn,
+ get_vif_fn, add_flow_int_fn, delete_flows_int_fn,
+ add_flow_tun_fn, delete_flows_tun_fn, add_flow_phys_fn,
+ delete_flows_phys_fn):
+ self.agent.port_bound(
+ self._port, self._net_uuid, network_type,
+ physical_network, segmentation_id, self._fixed_ips,
+ n_const.DEVICE_OWNER_DVR_INTERFACE, False)
+ lvm = self.agent.local_vlan_map[self._net_uuid]
+ phy_ofp = self.agent.dvr_agent.phys_ofports[physical_network]
+ int_ofp = self.agent.dvr_agent.int_ofports[physical_network]
+ expected_on_phys_br = [
+ mock.call(table=constants.LOCAL_VLAN_TRANSLATION,
+ priority=4,
+ in_port=phy_ofp,
+ dl_vlan=lvm.vlan,
+ actions="mod_vlan_vid:%s,normal" %
+ (lvm.segmentation_id)),
+ mock.call(table=constants.DVR_PROCESS_VLAN,
+ priority=2,
+ dl_vlan=lvm.vlan,
+ dl_dst=self._port.vif_mac,
+ actions="drop"),
+ mock.call(table=constants.DVR_PROCESS_VLAN,
+ priority=1,
+ dl_vlan=lvm.vlan,
+ dl_src=self._port.vif_mac,
+ actions="mod_dl_src:%s,resubmit(,%s)" %
+ (self.agent.dvr_agent.dvr_mac_address,
+ constants.LOCAL_VLAN_TRANSLATION))
+ ]
+ if ip_version == 4:
+ expected_on_phys_br.insert(1, mock.call(
+ proto='arp',
+ nw_dst=gateway_ip, actions='drop',
+ priority=3, table=constants.DVR_PROCESS_VLAN,
+ dl_vlan=lvm.vlan))
+ else:
+ expected_on_phys_br.insert(1, mock.call(
+ icmp_type=n_const.ICMPV6_TYPE_RA, proto='icmp6',
+ dl_src=self._port.vif_mac, actions='drop',
+ priority=3, table=constants.DVR_PROCESS_VLAN,
+ dl_vlan=lvm.vlan))
+ self.assertEqual(expected_on_phys_br,
+ add_flow_phys_fn.call_args_list)
+ self.agent.port_bound(self._compute_port, self._net_uuid,
+ network_type, physical_network,
+ segmentation_id,
+ self._compute_fixed_ips,
+ device_owner, False)
+ expected_on_int_br = [
+ mock.call(priority=3,
+ in_port=int_ofp,
+ dl_vlan=lvm.segmentation_id,
+ actions="mod_vlan_vid:%s,normal" % lvm.vlan),
+ mock.call(table=constants.DVR_TO_SRC_MAC_VLAN,
+ priority=4,
+ dl_dst=self._compute_port.vif_mac,
+ dl_vlan=lvm.segmentation_id,
+ actions="strip_vlan,mod_dl_src:%s,"
+ "output:%s" %
+ (gateway_mac,
+ self._compute_port.ofport))
+ ]
+ self.assertEqual(expected_on_int_br,
+ add_flow_int_fn.call_args_list)
+ expected_on_int_br = [
+ mock.call(in_port=self._port.ofport),
+ mock.call(in_port=self._compute_port.ofport)
+ ]
+ self.assertEqual(expected_on_int_br,
+ delete_flows_int_fn.call_args_list)
+ self.assertFalse(add_flow_tun_fn.called)
+ self.assertFalse(delete_flows_tun_fn.called)
+ self.assertFalse(delete_flows_phys_fn.called)
+
+ def _test_port_bound_for_dvr_on_vxlan_network(self, device_owner,
+ ip_version=4):
+ self._setup_for_dvr_test()
+ if ip_version == 4:
+ gateway_ip = '1.1.1.1'
+ cidr = '1.1.1.0/24'
+ else:
+ gateway_ip = '2001:100::1'
+ cidr = '2001:100::0/64'
+ network_type = p_const.TYPE_VXLAN
+ self._port.vif_mac = gateway_mac = 'aa:bb:cc:11:22:33'
+ self._compute_port.vif_mac = '77:88:99:00:11:22'
+ physical_network = self._physical_network
+ segmentation_id = self._segmentation_id
+ with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'set_db_attribute',
+ return_value=True):
+ with contextlib.nested(
+ mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'db_get_val',
+ return_value=self._old_local_vlan),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_subnet_for_dvr',
+ return_value={
+ 'gateway_ip': gateway_ip,
+ 'cidr': cidr,
+ 'ip_version': ip_version,
+ 'gateway_mac': gateway_mac}),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_ports_on_host_by_subnet',
+ return_value=[]),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'get_vif_port_by_id',
+ return_value=self._port),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows'),
+ mock.patch.object(
+ self.agent.dvr_agent.phys_brs[physical_network],
+ 'add_flow'),
+ mock.patch.object(
+ self.agent.dvr_agent.phys_brs[physical_network],
+ 'delete_flows')
+ ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn,
+ get_vif_fn, add_flow_int_fn, delete_flows_int_fn,
+ add_flow_tun_fn, delete_flows_tun_fn,
+ add_flow_phys_fn, delete_flows_phys_fn):
+ self.agent.port_bound(
+ self._port, self._net_uuid, network_type,
+ physical_network, segmentation_id, self._fixed_ips,
+ n_const.DEVICE_OWNER_DVR_INTERFACE, False)
+ lvm = self.agent.local_vlan_map[self._net_uuid]
+ expected_in_tun_br = [
+ mock.call(
+ table=constants.TUN_TABLE['vxlan'],
+ priority=1, tun_id=lvm.segmentation_id,
+ actions="mod_vlan_vid:%s,"
+ "resubmit(,%s)" %
+ (lvm.vlan, constants.DVR_NOT_LEARN)),
+ mock.call(
+ table=constants.DVR_PROCESS, priority=2,
+ dl_vlan=lvm.vlan,
+ dl_dst=self._port.vif_mac,
+ actions='drop'),
+ mock.call(
+ table=constants.DVR_PROCESS, priority=1,
+ dl_vlan=lvm.vlan,
+ dl_src=self._port.vif_mac,
+ actions="mod_dl_src:%s,resubmit(,%s)" % (
+ self.agent.dvr_agent.dvr_mac_address,
+ constants.PATCH_LV_TO_TUN))]
+ if ip_version == 4:
+ expected_in_tun_br.insert(1, mock.call(
+ proto='arp',
+ nw_dst=gateway_ip, actions='drop',
+ priority=3, table=constants.DVR_PROCESS,
+ dl_vlan=lvm.vlan))
+ else:
+ expected_in_tun_br.insert(1, mock.call(
+ icmp_type=n_const.ICMPV6_TYPE_RA,
+ proto='icmp6',
+ dl_src=self._port.vif_mac,
+ actions='drop',
+ priority=3, table=constants.DVR_PROCESS,
+ dl_vlan=lvm.vlan))
+ self.assertEqual(expected_in_tun_br,
+ add_flow_tun_fn.call_args_list)
+ self.agent.port_bound(self._compute_port, self._net_uuid,
+ network_type, physical_network,
+ segmentation_id,
+ self._compute_fixed_ips,
+ device_owner, False)
+ expected_in_int_br = [
+ mock.call(table=constants.DVR_TO_SRC_MAC, priority=4,
+ dl_dst=self._compute_port.vif_mac,
+ dl_vlan=lvm.vlan,
+ actions="strip_vlan,mod_dl_src:%s,"
+ "output:%s" %
+ (gateway_mac, self._compute_port.ofport))
+ ]
+ self.assertEqual(expected_in_int_br,
+ add_flow_int_fn.call_args_list)
+ self.assertFalse(add_flow_phys_fn.called)
+ expected_in_int_br = [
+ mock.call(in_port=self._port.ofport),
+ mock.call(in_port=self._compute_port.ofport)
+ ]
+ self.assertEqual(expected_in_int_br,
+ delete_flows_int_fn.call_args_list)
+ self.assertFalse(add_flow_phys_fn.called)
+ self.assertFalse(delete_flows_tun_fn.called)
+ self.assertFalse(delete_flows_phys_fn.called)
+
+ def test_port_bound_for_dvr_with_compute_ports(self):
+ self._test_port_bound_for_dvr_on_vlan_network(
+ device_owner="compute:None")
+ self._test_port_bound_for_dvr_on_vlan_network(
+ device_owner="compute:None", ip_version=6)
+ self._test_port_bound_for_dvr_on_vxlan_network(
+ device_owner="compute:None")
+ self._test_port_bound_for_dvr_on_vxlan_network(
+ device_owner="compute:None", ip_version=6)
+
+ def test_port_bound_for_dvr_with_lbaas_vip_ports(self):
+ self._test_port_bound_for_dvr_on_vlan_network(
+ device_owner=n_const.DEVICE_OWNER_LOADBALANCER)
+ self._test_port_bound_for_dvr_on_vlan_network(
+ device_owner=n_const.DEVICE_OWNER_LOADBALANCER, ip_version=6)
+ self._test_port_bound_for_dvr_on_vxlan_network(
+ device_owner=n_const.DEVICE_OWNER_LOADBALANCER)
+ self._test_port_bound_for_dvr_on_vxlan_network(
+ device_owner=n_const.DEVICE_OWNER_LOADBALANCER, ip_version=6)
+
+ def test_port_bound_for_dvr_with_dhcp_ports(self):
+ self._test_port_bound_for_dvr_on_vlan_network(
+ device_owner=n_const.DEVICE_OWNER_DHCP)
+ self._test_port_bound_for_dvr_on_vlan_network(
+ device_owner=n_const.DEVICE_OWNER_DHCP, ip_version=6)
+ self._test_port_bound_for_dvr_on_vxlan_network(
+ device_owner=n_const.DEVICE_OWNER_DHCP)
+ self._test_port_bound_for_dvr_on_vxlan_network(
+ device_owner=n_const.DEVICE_OWNER_DHCP, ip_version=6)
+
+ def test_port_bound_for_dvr_with_csnat_ports(self, ofport=10):
+ self._setup_for_dvr_test()
+ with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'set_db_attribute',
+ return_value=True):
+ with contextlib.nested(
+ mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'db_get_val',
+ return_value=self._old_local_vlan),
+ mock.patch.object(
+ self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
+ return_value={'gateway_ip': '1.1.1.1',
+ 'cidr': '1.1.1.0/24',
+ 'ip_version': 4,
+ 'gateway_mac': 'aa:bb:cc:11:22:33'}),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_ports_on_host_by_subnet',
+ return_value=[]),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'get_vif_port_by_id',
+ return_value=self._port),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
+ ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn,
+ get_vif_fn, add_flow_int_fn, delete_flows_int_fn,
+ add_flow_tun_fn, delete_flows_tun_fn):
+ self.agent.port_bound(
+ self._port, self._net_uuid, 'vxlan',
+ None, None, self._fixed_ips,
+ n_const.DEVICE_OWNER_ROUTER_SNAT,
+ False)
+ self.assertTrue(add_flow_int_fn.called)
+ self.assertTrue(delete_flows_int_fn.called)
+
+ def test_treat_devices_removed_for_dvr_interface(self, ofport=10):
+ self._test_treat_devices_removed_for_dvr_interface(ofport)
+ self._test_treat_devices_removed_for_dvr_interface(
+ ofport, ip_version=6)
+
+ def _test_treat_devices_removed_for_dvr_interface(self, ofport=10,
+ ip_version=4):
+ self._setup_for_dvr_test()
+ if ip_version == 4:
+ gateway_ip = '1.1.1.1'
+ cidr = '1.1.1.0/24'
+ else:
+ gateway_ip = '2001:100::1'
+ cidr = '2001:100::0/64'
+ with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'set_db_attribute',
+ return_value=True):
+ with contextlib.nested(
+ mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'db_get_val',
+ return_value=self._old_local_vlan),
+ mock.patch.object(
+ self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
+ return_value={'gateway_ip': gateway_ip,
+ 'cidr': cidr,
+ 'ip_version': ip_version,
+ 'gateway_mac': 'aa:bb:cc:11:22:33'}),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_ports_on_host_by_subnet',
+ return_value=[]),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'get_vif_port_by_id',
+ return_value=self._port),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
+ ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn,
+ get_vif_fn, add_flow_int_fn, delete_flows_int_fn,
+ add_flow_tun_fn, delete_flows_tun_fn):
+ self.agent.port_bound(
+ self._port, self._net_uuid, 'vxlan',
+ None, None, self._fixed_ips,
+ n_const.DEVICE_OWNER_DVR_INTERFACE,
+ False)
+ self.assertTrue(add_flow_tun_fn.called)
+ self.assertTrue(delete_flows_int_fn.called)
+
+ with contextlib.nested(
+ mock.patch.object(self.agent, 'reclaim_local_vlan'),
+ mock.patch.object(self.agent.plugin_rpc, 'update_device_down',
+ return_value=None),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
+ mock.patch.object(self.agent.dvr_agent.tun_br,
+ 'delete_flows')) as (reclaim_vlan_fn,
+ update_dev_down_fn,
+ delete_flows_int_fn,
+ delete_flows_tun_fn):
+ self.agent.treat_devices_removed([self._port.vif_id])
+ if ip_version == 4:
+ expected = [mock.call(
+ proto='arp',
+ nw_dst=gateway_ip,
+ table=constants.DVR_PROCESS,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan))]
+ else:
+ expected = [mock.call(
+ icmp_type=n_const.ICMPV6_TYPE_RA, proto='icmp6',
+ dl_src='aa:bb:cc:11:22:33',
+ table=constants.DVR_PROCESS,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan))]
+ expected.extend([
+ mock.call(
+ table=constants.DVR_PROCESS,
+ dl_dst=self._port.vif_mac,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan)),
+ mock.call(
+ table=constants.DVR_PROCESS,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan),
+ dl_src=self._port.vif_mac)
+ ])
+ self.assertEqual(expected, delete_flows_tun_fn.call_args_list)
+
+ def _test_treat_devices_removed_for_dvr(self, device_owner, ip_version=4):
+ self._setup_for_dvr_test()
+ if ip_version == 4:
+ gateway_ip = '1.1.1.1'
+ cidr = '1.1.1.0/24'
+ else:
+ gateway_ip = '2001:100::1'
+ cidr = '2001:100::0/64'
+ with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'set_db_attribute',
+ return_value=True):
+ with contextlib.nested(
+ mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'db_get_val',
+ return_value=self._old_local_vlan),
+ mock.patch.object(
+ self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
+ return_value={'gateway_ip': gateway_ip,
+ 'cidr': cidr,
+ 'ip_version': ip_version,
+ 'gateway_mac': 'aa:bb:cc:11:22:33'}),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_ports_on_host_by_subnet',
+ return_value=[]),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'get_vif_port_by_id',
+ return_value=self._port),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
+ ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn,
+ get_vif_fn, add_flow_int_fn, delete_flows_int_fn,
+ add_flow_tun_fn, delete_flows_tun_fn):
+ self.agent.port_bound(
+ self._port, self._net_uuid, 'vxlan',
+ None, None, self._fixed_ips,
+ n_const.DEVICE_OWNER_DVR_INTERFACE,
+ False)
+ self.agent.port_bound(self._compute_port,
+ self._net_uuid, 'vxlan',
+ None, None,
+ self._compute_fixed_ips,
+ device_owner, False)
+ self.assertTrue(add_flow_tun_fn.called)
+ self.assertTrue(add_flow_int_fn.called)
+ self.assertTrue(delete_flows_int_fn.called)
+
+ with contextlib.nested(
+ mock.patch.object(self.agent, 'reclaim_local_vlan'),
+ mock.patch.object(self.agent.plugin_rpc, 'update_device_down',
+ return_value=None),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'delete_flows')) as (reclaim_vlan_fn,
+ update_dev_down_fn,
+ delete_flows_int_fn):
+ self.agent.treat_devices_removed([self._compute_port.vif_id])
+ expected = [
+ mock.call(
+ table=constants.DVR_TO_SRC_MAC,
+ dl_dst=self._compute_port.vif_mac,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan))]
+ self.assertEqual(expected, delete_flows_int_fn.call_args_list)
+
+ def test_treat_devices_removed_for_dvr_with_compute_ports(self):
+ self._test_treat_devices_removed_for_dvr(
+ device_owner="compute:None")
+ self._test_treat_devices_removed_for_dvr(
+ device_owner="compute:None", ip_version=6)
+
+ def test_treat_devices_removed_for_dvr_with_lbaas_vip_ports(self):
+ self._test_treat_devices_removed_for_dvr(
+ device_owner=n_const.DEVICE_OWNER_LOADBALANCER)
+ self._test_treat_devices_removed_for_dvr(
+ device_owner=n_const.DEVICE_OWNER_LOADBALANCER, ip_version=6)
+
+ def test_treat_devices_removed_for_dvr_with_dhcp_ports(self):
+ self._test_treat_devices_removed_for_dvr(
+ device_owner=n_const.DEVICE_OWNER_DHCP)
+ self._test_treat_devices_removed_for_dvr(
+ device_owner=n_const.DEVICE_OWNER_DHCP, ip_version=6)
+
+ def test_treat_devices_removed_for_dvr_csnat_port(self, ofport=10):
+ self._setup_for_dvr_test()
+ with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'set_db_attribute',
+ return_value=True):
+ with contextlib.nested(
+ mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
+ 'db_get_val',
+ return_value=self._old_local_vlan),
+ mock.patch.object(
+ self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
+ return_value={'gateway_ip': '1.1.1.1',
+ 'cidr': '1.1.1.0/24',
+ 'ip_version': 4,
+ 'gateway_mac': 'aa:bb:cc:11:22:33'}),
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_ports_on_host_by_subnet',
+ return_value=[]),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'get_vif_port_by_id',
+ return_value=self._port),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
+ ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn,
+ get_vif_fn, add_flow_int_fn, delete_flows_int_fn,
+ add_flow_tun_fn, delete_flows_tun_fn):
+ self.agent.port_bound(
+ self._port, self._net_uuid, 'vxlan',
+ None, None, self._fixed_ips,
+ n_const.DEVICE_OWNER_ROUTER_SNAT,
+ False)
+ self.assertTrue(add_flow_int_fn.called)
+ self.assertTrue(delete_flows_int_fn.called)
+
+ with contextlib.nested(
+ mock.patch.object(self.agent, 'reclaim_local_vlan'),
+ mock.patch.object(self.agent.plugin_rpc, 'update_device_down',
+ return_value=None),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'delete_flows')) as (reclaim_vlan_fn,
+ update_dev_down_fn,
+ delete_flows_int_fn):
+ self.agent.treat_devices_removed([self._port.vif_id])
+ self.assertTrue(delete_flows_int_fn.called)
+
+ def test_setup_dvr_flows_on_int_br(self):
+ self._setup_for_dvr_test()
+ with contextlib.nested(
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'remove_all_flows'),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
+ mock.patch.object(
+ self.agent.dvr_agent.plugin_rpc,
+ 'get_dvr_mac_address_list',
+ return_value=[{'host': 'cn1',
+ 'mac_address': 'aa:bb:cc:dd:ee:ff'},
+ {'host': 'cn2',
+ 'mac_address': '11:22:33:44:55:66'}])) as \
+ (remove_flows_fn, add_int_flow_fn, add_tun_flow_fn,
+ get_mac_list_fn):
+ self.agent.dvr_agent.setup_dvr_flows_on_integ_br()
+ self.assertTrue(self.agent.dvr_agent.in_distributed_mode())
+ physical_networks = self.agent.dvr_agent.bridge_mappings.keys()
+ ioport = self.agent.dvr_agent.int_ofports[physical_networks[0]]
+ expected = [
+ mock.call(table=constants.CANARY_TABLE,
+ priority=0,
+ actions="drop"),
+ mock.call(table=constants.DVR_TO_SRC_MAC,
+ priority=1,
+ actions="drop"),
+ mock.call(table=constants.DVR_TO_SRC_MAC_VLAN,
+ priority=1,
+ actions="drop"),
+ mock.call(table=constants.LOCAL_SWITCHING,
+ priority=1,
+ actions="normal"),
+ mock.call(
+ table=constants.LOCAL_SWITCHING, priority=2,
+ actions="drop",
+ in_port=ioport)]
+ self.assertTrue(remove_flows_fn.called)
+ self.assertEqual(expected, add_int_flow_fn.call_args_list)
+ self.assertEqual(add_int_flow_fn.call_count, 5)
+
+ def test_get_dvr_mac_address(self):
+ self._setup_for_dvr_test()
+ self.agent.dvr_agent.dvr_mac_address = None
+ with mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_dvr_mac_address_by_host',
+ return_value={'host': 'cn1',
+ 'mac_address': 'aa:22:33:44:55:66'}):
+ self.agent.dvr_agent.get_dvr_mac_address()
+ self.assertEqual('aa:22:33:44:55:66',
+ self.agent.dvr_agent.dvr_mac_address)
+ self.assertTrue(self.agent.dvr_agent.in_distributed_mode())
+
+ def test_get_dvr_mac_address_exception(self):
+ self._setup_for_dvr_test()
+ self.agent.dvr_agent.dvr_mac_address = None
+ with contextlib.nested(
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_dvr_mac_address_by_host',
+ side_effect=messaging.RemoteError),
+ mock.patch.object(self.agent.dvr_agent.int_br,
+ 'add_flow')) as (gd_mac, add_int_flow_fn):
+
+ self.agent.dvr_agent.get_dvr_mac_address()
+ self.assertIsNone(self.agent.dvr_agent.dvr_mac_address)
+ self.assertFalse(self.agent.dvr_agent.in_distributed_mode())
+ self.assertEqual(add_int_flow_fn.call_count, 1)
+
+ def test_get_dvr_mac_address_retried(self):
+ valid_entry = {'host': 'cn1', 'mac_address': 'aa:22:33:44:55:66'}
+ raise_timeout = messaging.MessagingTimeout()
+ # Raise a timeout the first 2 times it calls get_dvr_mac_address()
+ self._setup_for_dvr_test()
+ self.agent.dvr_agent.dvr_mac_address = None
+ with mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_dvr_mac_address_by_host',
+ side_effect=(raise_timeout, raise_timeout,
+ valid_entry)):
+ self.agent.dvr_agent.get_dvr_mac_address()
+ self.assertEqual('aa:22:33:44:55:66',
+ self.agent.dvr_agent.dvr_mac_address)
+ self.assertTrue(self.agent.dvr_agent.in_distributed_mode())
+ self.assertEqual(self.agent.dvr_agent.plugin_rpc.
+ get_dvr_mac_address_by_host.call_count, 3)
+
+ def test_get_dvr_mac_address_retried_max(self):
+ raise_timeout = messaging.MessagingTimeout()
+ # Raise a timeout every time until we give up, currently 5 tries
+ self._setup_for_dvr_test()
+ self.agent.dvr_agent.dvr_mac_address = None
+ with contextlib.nested(
+ mock.patch.object(self.agent.dvr_agent.plugin_rpc,
+ 'get_dvr_mac_address_by_host',
+ side_effect=raise_timeout),
+ mock.patch.object(utils, "execute"),
+ ) as (rpc_mock, execute_mock):
+ self.agent.dvr_agent.get_dvr_mac_address()
+ self.assertIsNone(self.agent.dvr_agent.dvr_mac_address)
+ self.assertFalse(self.agent.dvr_agent.in_distributed_mode())
+ self.assertEqual(self.agent.dvr_agent.plugin_rpc.
+ get_dvr_mac_address_by_host.call_count, 5)
+
+ def test_dvr_mac_address_update(self):
+ self._setup_for_dvr_test()
+ newhost = 'cn2'
+ newmac = 'aa:bb:cc:dd:ee:ff'
+ int_ofport = self.agent.dvr_agent.int_ofports['physeth1']
+ patch_int_ofport = self.agent.dvr_agent.patch_int_ofport
+ patch_tun_ofport = self.agent.dvr_agent.patch_tun_ofport
+ with contextlib.nested(
+ mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
+ mock.patch.object(self.agent.dvr_agent.phys_brs['physeth1'],
+ 'add_flow')
+ ) as (add_flow_fn, add_flow_tn_fn, del_flows_fn, add_flow_phys_fn):
+ self.agent.dvr_agent.\
+ dvr_mac_address_update(
+ dvr_macs=[{'host': newhost,
+ 'mac_address': newmac}])
+ expected = [
+ mock.call(table=constants.LOCAL_SWITCHING,
+ priority=4,
+ in_port=int_ofport,
+ dl_src=newmac,
+ actions="resubmit(,%s)" %
+ constants.DVR_TO_SRC_MAC_VLAN),
+ mock.call(table=constants.LOCAL_SWITCHING,
+ priority=2,
+ in_port=patch_tun_ofport,
+ dl_src=newmac,
+ actions="resubmit(,%s)" %
+ constants.DVR_TO_SRC_MAC)]
+ self.assertEqual(expected, add_flow_fn.call_args_list)
+ add_flow_phys_fn.assert_called_with(
+ table=constants.DVR_NOT_LEARN_VLAN,
+ priority=2,
+ dl_src=newmac,
+ actions="output:%s" %
+ self.agent.dvr_agent.phys_ofports['physeth1'])
+ add_flow_tn_fn.assert_called_with(table=constants.DVR_NOT_LEARN,
+ priority=1,
+ dl_src=newmac,
+ actions="output:%s"
+ % patch_int_ofport)
+ self.assertFalse(del_flows_fn.called)
+ with contextlib.nested(
+ mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
+ mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows'),
+ mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
+ mock.patch.object(self.agent.dvr_agent.phys_brs['physeth1'],
+ 'delete_flows'),
+ ) as (add_flow_fn, del_flows_tn_fn, del_flows_fn, del_flows_phys_fn):
+ self.agent.dvr_agent.dvr_mac_address_update(dvr_macs=[])
+ ioport = self.agent.dvr_agent.int_ofports['physeth1']
+ expected = [
+ mock.call(table=constants.LOCAL_SWITCHING,
+ in_port=ioport,
+ dl_src=newmac),
+ mock.call(table=constants.LOCAL_SWITCHING,
+ in_port=patch_tun_ofport,
+ dl_src=newmac)]
+ self.assertEqual(expected, del_flows_fn.call_args_list)
+ del_flows_phys_fn.asert_called_with(
+ table=constants.DVR_NOT_LEARN_VLAN,
+ dl_src=newmac)
+ del_flows_tn_fn.assert_called_with(table=constants.DVR_NOT_LEARN,
+ dl_src=newmac)
+ self.assertFalse(add_flow_fn.called)
import mock
import netaddr
from oslo.config import cfg
-from oslo import messaging
import testtools
from neutron.agent.linux import async_process
self.assertFalse(set_ovs_db_func.called)
self.assertFalse(delete_flows_func.called)
- def _setup_for_dvr_test(self, ofport=10):
- self._port = mock.Mock()
- self._port.ofport = ofport
- self._port.vif_id = "1234-5678-90"
- self.agent.enable_distributed_routing = True
- self.agent.enable_tunneling = True
- self.agent.patch_tun_ofport = 1
- self.agent.patch_int_ofport = 2
- self.agent.dvr_agent.local_ports = {}
- self.agent.local_vlan_map = {}
- self.agent.dvr_agent.enable_distributed_routing = True
- self.agent.dvr_agent.enable_tunneling = True
- self.agent.dvr_agent.patch_tun_ofport = 1
- self.agent.dvr_agent.patch_int_ofport = 2
- self.agent.dvr_agent.tun_br = mock.Mock()
- self.agent.dvr_agent.local_dvr_map = {}
- self.agent.dvr_agent.registered_dvr_macs = set()
- self.agent.dvr_agent.dvr_mac_address = 'aa:22:33:44:55:66'
- self._net_uuid = 'my-net-uuid'
- self._fixed_ips = [{'subnet_id': 'my-subnet-uuid',
- 'ip_address': '1.1.1.1'}]
- self._compute_port = mock.Mock()
- self._compute_port.ofport = 20
- self._compute_port.vif_id = "1234-5678-91"
- self._old_local_vlan = None
- self._compute_fixed_ips = [{'subnet_id': 'my-subnet-uuid',
- 'ip_address': '1.1.1.3'}]
-
def test_port_bound_deletes_flows_for_valid_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_bound_for_dvr_interface(self, ofport=10):
- self._setup_for_dvr_test()
- with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
- 'set_db_attribute',
- return_value=True):
- with contextlib.nested(
- mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
- 'db_get_val',
- return_value=self._old_local_vlan),
- mock.patch.object(
- self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
- return_value={'gateway_ip': '1.1.1.1',
- 'cidr': '1.1.1.0/24',
- 'ip_version': 4,
- 'gateway_mac': 'aa:bb:cc:11:22:33'}),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_ports_on_host_by_subnet',
- return_value=[]),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'get_vif_port_by_id',
- return_value=self._port),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
- ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn,
- get_vif_fn, add_flow_int_fn, delete_flows_int_fn,
- add_flow_tun_fn, delete_flows_tun_fn):
- self.agent.port_bound(
- self._port, self._net_uuid, 'vxlan',
- None, None, self._fixed_ips,
- n_const.DEVICE_OWNER_DVR_INTERFACE,
- False)
- self.assertTrue(add_flow_tun_fn.called)
- self.assertTrue(delete_flows_int_fn.called)
-
- def _test_port_bound_for_dvr(self, device_owner, ip_version=4):
- self._setup_for_dvr_test()
- if ip_version == 4:
- gateway_ip = '1.1.1.1'
- cidr = '1.1.1.0/24'
- else:
- gateway_ip = '2001:100::1'
- cidr = '2001:100::0/64'
- with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
- 'set_db_attribute',
- return_value=True):
- with contextlib.nested(
- mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
- 'db_get_val',
- return_value=self._old_local_vlan),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_subnet_for_dvr',
- return_value={
- 'gateway_ip': gateway_ip,
- 'cidr': cidr,
- 'ip_version': ip_version,
- 'gateway_mac': 'aa:bb:cc:11:22:33'}),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_ports_on_host_by_subnet',
- return_value=[]),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'get_vif_port_by_id',
- return_value=self._port),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
- ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn,
- get_vif_fn, add_flow_int_fn, delete_flows_int_fn,
- add_flow_tun_fn, delete_flows_tun_fn):
- self.agent.port_bound(
- self._port, self._net_uuid, 'vxlan',
- None, None, self._fixed_ips,
- n_const.DEVICE_OWNER_DVR_INTERFACE,
- False)
- expected = [
- mock.call(
- table=constants.TUN_TABLE['vxlan'],
- priority=1, tun_id=None,
- actions="mod_vlan_vid:%s,"
- "resubmit(,%s)" %
- (self.agent.local_vlan_map[self._net_uuid].vlan,
- constants.DVR_NOT_LEARN)),
- mock.call(
- table=constants.DVR_PROCESS, priority=2,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan),
- dl_dst=self._port.vif_mac,
- actions='drop'),
- mock.call(
- table=constants.DVR_PROCESS, priority=1,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan),
- dl_src=self._port.vif_mac,
- actions="mod_dl_src:%s,resubmit(,%s)" % (
- self.agent.dvr_agent.dvr_mac_address,
- constants.PATCH_LV_TO_TUN))]
- if ip_version == 4:
- expected.insert(1, mock.call(
- proto='arp',
- nw_dst=gateway_ip, actions='drop',
- priority=3, table=constants.DVR_PROCESS,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan)))
- else:
- expected.insert(1, mock.call(
- icmp_type=n_const.ICMPV6_TYPE_RA, proto='icmp6',
- dl_src='aa:bb:cc:11:22:33', actions='drop',
- priority=3, table=constants.DVR_PROCESS,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan)))
-
- self.assertEqual(expected, add_flow_tun_fn.call_args_list)
- self.agent.port_bound(self._compute_port, self._net_uuid,
- 'vxlan', None, None,
- self._compute_fixed_ips,
- device_owner, False)
- expected = [
- mock.call(table=constants.DVR_TO_SRC_MAC, priority=4,
- dl_dst=self._compute_port.vif_mac,
- dl_vlan=self.agent.local_vlan_map[self._net_uuid].vlan,
- actions="strip_vlan,mod_dl_src:%s,"
- "output:%s" %
- ('aa:bb:cc:11:22:33', self._compute_port.ofport))
- ]
- if ip_version == 4:
- expected.append(mock.call(
- table=constants.DVR_TO_SRC_MAC,
- priority=2, proto='ip',
- nw_dst=cidr,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan),
- actions="strip_vlan,mod_dl_src:%s,"
- "output:%s" %
- ('aa:bb:cc:11:22:33', self._compute_port.ofport)))
- else:
- expected.append(mock.call(
- table=constants.DVR_TO_SRC_MAC,
- priority=2, proto='ipv6',
- ipv6_dst=cidr,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan),
- actions="strip_vlan,mod_dl_src:%s,"
- "output:%s" %
- ('aa:bb:cc:11:22:33', self._compute_port.ofport)))
- self.assertEqual(expected, add_flow_int_fn.call_args_list)
- self.assertTrue(delete_flows_int_fn.called)
-
- def test_port_bound_for_dvr_with_compute_ports(self):
- self._test_port_bound_for_dvr(
- device_owner="compute:None")
- self._test_port_bound_for_dvr(
- device_owner="compute:None", ip_version=6)
-
- def test_port_bound_for_dvr_with_lbaas_vip_ports(self):
- self._test_port_bound_for_dvr(
- device_owner=n_const.DEVICE_OWNER_LOADBALANCER)
- self._test_port_bound_for_dvr(
- device_owner=n_const.DEVICE_OWNER_LOADBALANCER, ip_version=6)
-
- def test_port_bound_for_dvr_with_dhcp_ports(self):
- self._test_port_bound_for_dvr(
- device_owner=n_const.DEVICE_OWNER_DHCP)
- self._test_port_bound_for_dvr(
- device_owner=n_const.DEVICE_OWNER_DHCP, ip_version=6)
-
- def test_port_bound_for_dvr_with_csnat_ports(self, ofport=10):
- self._setup_for_dvr_test()
- with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
- 'set_db_attribute',
- return_value=True):
- with contextlib.nested(
- mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
- 'db_get_val',
- return_value=self._old_local_vlan),
- mock.patch.object(
- self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
- return_value={'gateway_ip': '1.1.1.1',
- 'cidr': '1.1.1.0/24',
- 'ip_version': 4,
- 'gateway_mac': 'aa:bb:cc:11:22:33'}),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_ports_on_host_by_subnet',
- return_value=[]),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'get_vif_port_by_id',
- return_value=self._port),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
- ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn,
- get_vif_fn, add_flow_int_fn, delete_flows_int_fn,
- add_flow_tun_fn, delete_flows_tun_fn):
- self.agent.port_bound(
- self._port, self._net_uuid, 'vxlan',
- None, None, self._fixed_ips,
- n_const.DEVICE_OWNER_ROUTER_SNAT,
- False)
- self.assertTrue(add_flow_int_fn.called)
- self.assertTrue(delete_flows_int_fn.called)
-
- def test_treat_devices_removed_for_dvr_interface(self, ofport=10):
- self._test_treat_devices_removed_for_dvr_interface(ofport)
- self._test_treat_devices_removed_for_dvr_interface(
- ofport, ip_version=6)
-
- def _test_treat_devices_removed_for_dvr_interface(self, ofport=10,
- ip_version=4):
- self._setup_for_dvr_test()
- if ip_version == 4:
- gateway_ip = '1.1.1.1'
- cidr = '1.1.1.0/24'
- else:
- gateway_ip = '2001:100::1'
- cidr = '2001:100::0/64'
- with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
- 'set_db_attribute',
- return_value=True):
- with contextlib.nested(
- mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
- 'db_get_val',
- return_value=self._old_local_vlan),
- mock.patch.object(
- self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
- return_value={'gateway_ip': gateway_ip,
- 'cidr': cidr,
- 'ip_version': ip_version,
- 'gateway_mac': 'aa:bb:cc:11:22:33'}),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_ports_on_host_by_subnet',
- return_value=[]),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'get_vif_port_by_id',
- return_value=self._port),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
- ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn,
- get_vif_fn, add_flow_int_fn, delete_flows_int_fn,
- add_flow_tun_fn, delete_flows_tun_fn):
- self.agent.port_bound(
- self._port, self._net_uuid, 'vxlan',
- None, None, self._fixed_ips,
- n_const.DEVICE_OWNER_DVR_INTERFACE,
- False)
- self.assertTrue(add_flow_tun_fn.called)
- self.assertTrue(delete_flows_int_fn.called)
-
- with contextlib.nested(
- mock.patch.object(self.agent, 'reclaim_local_vlan'),
- mock.patch.object(self.agent.plugin_rpc, 'update_device_down',
- return_value=None),
- mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
- mock.patch.object(self.agent.dvr_agent.tun_br,
- 'delete_flows')) as (reclaim_vlan_fn,
- update_dev_down_fn,
- delete_flows_int_fn,
- delete_flows_tun_fn):
- self.agent.treat_devices_removed([self._port.vif_id])
- if ip_version == 4:
- expected = [mock.call(
- table=constants.DVR_TO_SRC_MAC,
- nw_dst=cidr,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan),
- proto='ip')]
- else:
- expected = [mock.call(
- table=constants.DVR_TO_SRC_MAC,
- ipv6_dst=cidr,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan),
- proto='ipv6')]
- self.assertEqual(expected,
- delete_flows_int_fn.call_args_list)
- if ip_version == 4:
- expected = [mock.call(
- proto='arp',
- nw_dst=gateway_ip,
- table=constants.DVR_PROCESS,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan))]
- else:
- expected = [mock.call(
- icmp_type=n_const.ICMPV6_TYPE_RA, proto='icmp6',
- dl_src='aa:bb:cc:11:22:33',
- table=constants.DVR_PROCESS,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan))]
- expected.extend([
- mock.call(
- table=constants.DVR_PROCESS,
- dl_dst=self._port.vif_mac,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan)),
- mock.call(
- table=constants.DVR_PROCESS,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan),
- dl_src=self._port.vif_mac)
- ])
- self.assertEqual(expected, delete_flows_tun_fn.call_args_list)
-
- def _test_treat_devices_removed_for_dvr(self, device_owner, ip_version=4):
- self._setup_for_dvr_test()
- if ip_version == 4:
- gateway_ip = '1.1.1.1'
- cidr = '1.1.1.0/24'
- else:
- gateway_ip = '2001:100::1'
- cidr = '2001:100::0/64'
- with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
- 'set_db_attribute',
- return_value=True):
- with contextlib.nested(
- mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
- 'db_get_val',
- return_value=self._old_local_vlan),
- mock.patch.object(
- self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
- return_value={'gateway_ip': gateway_ip,
- 'cidr': cidr,
- 'ip_version': ip_version,
- 'gateway_mac': 'aa:bb:cc:11:22:33'}),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_ports_on_host_by_subnet',
- return_value=[]),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'get_vif_port_by_id',
- return_value=self._port),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
- ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn,
- get_vif_fn, add_flow_int_fn, delete_flows_int_fn,
- add_flow_tun_fn, delete_flows_tun_fn):
- self.agent.port_bound(
- self._port, self._net_uuid, 'vxlan',
- None, None, self._fixed_ips,
- n_const.DEVICE_OWNER_DVR_INTERFACE,
- False)
- self.agent.port_bound(self._compute_port,
- self._net_uuid, 'vxlan',
- None, None,
- self._compute_fixed_ips,
- device_owner, False)
- self.assertTrue(add_flow_tun_fn.called)
- self.assertTrue(add_flow_int_fn.called)
- self.assertTrue(delete_flows_int_fn.called)
-
- with contextlib.nested(
- mock.patch.object(self.agent, 'reclaim_local_vlan'),
- mock.patch.object(self.agent.plugin_rpc, 'update_device_down',
- return_value=None),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'delete_flows')) as (reclaim_vlan_fn,
- update_dev_down_fn,
- delete_flows_int_fn):
- self.agent.treat_devices_removed([self._compute_port.vif_id])
- expected = [
- mock.call(
- table=constants.DVR_TO_SRC_MAC,
- dl_dst=self._compute_port.vif_mac,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan))]
- if ip_version == 4:
- expected.append(mock.call(
- table=constants.DVR_TO_SRC_MAC,
- proto='ip', nw_dst=cidr,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan))
- )
- else:
- expected.append(mock.call(
- table=constants.DVR_TO_SRC_MAC,
- proto='ipv6', ipv6_dst=cidr,
- dl_vlan=(
- self.agent.local_vlan_map[self._net_uuid].vlan))
- )
- self.assertEqual(expected, delete_flows_int_fn.call_args_list)
-
- def test_treat_devices_removed_for_dvr_with_compute_ports(self):
- self._test_treat_devices_removed_for_dvr(
- device_owner="compute:None")
- self._test_treat_devices_removed_for_dvr(
- device_owner="compute:None", ip_version=6)
-
- def test_treat_devices_removed_for_dvr_with_lbaas_vip_ports(self):
- self._test_treat_devices_removed_for_dvr(
- device_owner=n_const.DEVICE_OWNER_LOADBALANCER)
- self._test_treat_devices_removed_for_dvr(
- device_owner=n_const.DEVICE_OWNER_LOADBALANCER, ip_version=6)
-
- def test_treat_devices_removed_for_dvr_with_dhcp_ports(self):
- self._test_treat_devices_removed_for_dvr(
- device_owner=n_const.DEVICE_OWNER_DHCP)
- self._test_treat_devices_removed_for_dvr(
- device_owner=n_const.DEVICE_OWNER_DHCP, ip_version=6)
-
- def test_treat_devices_removed_for_dvr_csnat_port(self, ofport=10):
- self._setup_for_dvr_test()
- with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
- 'set_db_attribute',
- return_value=True):
- with contextlib.nested(
- mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
- 'db_get_val',
- return_value=self._old_local_vlan),
- mock.patch.object(
- self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
- return_value={'gateway_ip': '1.1.1.1',
- 'cidr': '1.1.1.0/24',
- 'ip_version': 4,
- 'gateway_mac': 'aa:bb:cc:11:22:33'}),
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_ports_on_host_by_subnet',
- return_value=[]),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'get_vif_port_by_id',
- return_value=self._port),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
- ) as (get_ovs_db_func, get_subnet_fn, get_cphost_fn,
- get_vif_fn, add_flow_int_fn, delete_flows_int_fn,
- add_flow_tun_fn, delete_flows_tun_fn):
- self.agent.port_bound(
- self._port, self._net_uuid, 'vxlan',
- None, None, self._fixed_ips,
- n_const.DEVICE_OWNER_ROUTER_SNAT,
- False)
- self.assertTrue(add_flow_int_fn.called)
- self.assertTrue(delete_flows_int_fn.called)
-
- with contextlib.nested(
- mock.patch.object(self.agent, 'reclaim_local_vlan'),
- mock.patch.object(self.agent.plugin_rpc, 'update_device_down',
- return_value=None),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'delete_flows')) as (reclaim_vlan_fn,
- update_dev_down_fn,
- delete_flows_int_fn):
- self.agent.treat_devices_removed([self._port.vif_id])
- self.assertTrue(delete_flows_int_fn.called)
-
- def test_setup_dvr_flows_on_int_br(self):
- self._setup_for_dvr_test()
- with contextlib.nested(
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'remove_all_flows'),
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(
- self.agent.dvr_agent.plugin_rpc,
- 'get_dvr_mac_address_list',
- return_value=[{'host': 'cn1',
- 'mac_address': 'aa:bb:cc:dd:ee:ff'},
- {'host': 'cn2',
- 'mac_address': '11:22:33:44:55:66'}])) as \
- (remove_flows_fn, add_int_flow_fn, add_tun_flow_fn,
- get_mac_list_fn):
- self.agent.dvr_agent.setup_dvr_flows_on_integ_tun_br()
- self.assertTrue(self.agent.dvr_agent.in_distributed_mode())
- self.assertTrue(remove_flows_fn.called)
- self.assertEqual(add_int_flow_fn.call_count, 5)
- self.assertEqual(add_tun_flow_fn.call_count, 5)
-
- def test_get_dvr_mac_address(self):
- self._setup_for_dvr_test()
- self.agent.dvr_agent.dvr_mac_address = None
- with mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_dvr_mac_address_by_host',
- return_value={'host': 'cn1',
- 'mac_address': 'aa:22:33:44:55:66'}):
-
- self.agent.dvr_agent.get_dvr_mac_address()
- self.assertEqual('aa:22:33:44:55:66',
- self.agent.dvr_agent.dvr_mac_address)
- self.assertTrue(self.agent.dvr_agent.in_distributed_mode())
-
- def test_get_dvr_mac_address_exception(self):
- self._setup_for_dvr_test()
- self.agent.dvr_agent.dvr_mac_address = None
- with contextlib.nested(
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_dvr_mac_address_by_host',
- side_effect=messaging.RemoteError),
- mock.patch.object(self.agent.dvr_agent.int_br,
- 'add_flow')) as (gd_mac, add_int_flow_fn):
-
- self.agent.dvr_agent.get_dvr_mac_address()
- self.assertIsNone(self.agent.dvr_agent.dvr_mac_address)
- self.assertFalse(self.agent.dvr_agent.in_distributed_mode())
- self.assertEqual(add_int_flow_fn.call_count, 1)
-
- def test_get_dvr_mac_address_retried(self):
- valid_entry = {'host': 'cn1', 'mac_address': 'aa:22:33:44:55:66'}
- raise_timeout = messaging.MessagingTimeout()
- # Raise a timeout the first 2 times it calls get_dvr_mac_address()
- self._setup_for_dvr_test()
- self.agent.dvr_agent.dvr_mac_address = None
- with mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_dvr_mac_address_by_host',
- side_effect=(raise_timeout, raise_timeout,
- valid_entry)):
-
- self.agent.dvr_agent.get_dvr_mac_address()
- self.assertEqual('aa:22:33:44:55:66',
- self.agent.dvr_agent.dvr_mac_address)
- self.assertTrue(self.agent.dvr_agent.in_distributed_mode())
- self.assertEqual(self.agent.dvr_agent.plugin_rpc.
- get_dvr_mac_address_by_host.call_count, 3)
-
- def test_get_dvr_mac_address_retried_max(self):
- raise_timeout = messaging.MessagingTimeout()
- # Raise a timeout every time until we give up, currently 5 tries
- self._setup_for_dvr_test()
- self.agent.dvr_agent.dvr_mac_address = None
- with contextlib.nested(
- mock.patch.object(self.agent.dvr_agent.plugin_rpc,
- 'get_dvr_mac_address_by_host',
- side_effect=raise_timeout),
- mock.patch.object(utils, "execute"),
- ) as (rpc_mock, execute_mock):
- self.agent.dvr_agent.get_dvr_mac_address()
- self.assertIsNone(self.agent.dvr_agent.dvr_mac_address)
- self.assertFalse(self.agent.dvr_agent.in_distributed_mode())
- self.assertEqual(self.agent.dvr_agent.plugin_rpc.
- get_dvr_mac_address_by_host.call_count, 5)
-
def _test_port_dead(self, cur_tag=None):
port = mock.Mock()
port.ofport = 1
self.agent.reclaim_local_vlan('net2')
del_port_fn.assert_called_once_with('gre-02020202')
- def test_dvr_mac_address_update(self):
- self._setup_for_dvr_test()
- with contextlib.nested(
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows'),
- #mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows')
- ) as (add_flow_fn, add_flow_tn_fn, del_flows_fn):
- self.agent.dvr_agent.\
- dvr_mac_address_update(
- dvr_macs=[{'host': 'cn2',
- 'mac_address': 'aa:bb:cc:dd:ee:ff'}])
- add_flow_tn_fn.assert_called_with(table=constants.DVR_NOT_LEARN,
- priority=1,
- dl_src='aa:bb:cc:dd:ee:ff',
- actions="output:%s"
- % self.agent.patch_int_ofport
- )
- self.assertFalse(del_flows_fn.called)
- with contextlib.nested(
- mock.patch.object(self.agent.dvr_agent.int_br, 'add_flow'),
- mock.patch.object(self.agent.dvr_agent.tun_br, 'delete_flows'),
- mock.patch.object(self.agent.dvr_agent.int_br, 'delete_flows')
- ) as (add_flow_fn, del_flows_tn_fn, del_flows_fn):
- self.agent.dvr_agent.dvr_mac_address_update(dvr_macs=[])
- del_flows_tn_fn.assert_called_with(table=constants.DVR_NOT_LEARN,
- dl_src='aa:bb:cc:dd:ee:ff')
- self.assertFalse(add_flow_fn.called)
-
def test_daemon_loop_uses_polling_manager(self):
with mock.patch(
'neutron.agent.linux.polling.get_polling_manager') as mock_get_pm: