ovs: make vlanmanager to handle more vlan mapping per network

This change is updating the vlanmanager data structure to handle for a
given network more than one vlan mapping. This is a prerequisite work
needed to progress on accepting several segments per network per
host.

The work done here is trying to avoid changing logic in the
current implementation. Unit test should not have value updated,
but probably signatures changed.

Partial-Bug: #1956435
Partial-Bug: #1764738
Signed-off-by: Sahid Orentino Ferdjaoui <sahid.ferdjaoui@industrialdiscipline.com>
Change-Id: Ic3c147136549b17aea0fe78e930a41a5b33ab9d8
This commit is contained in:
Sahid Orentino Ferdjaoui 2022-04-27 09:03:55 +02:00
parent 7dfe41ab8f
commit 6ec0bc70a7
8 changed files with 278 additions and 171 deletions

View File

@ -232,7 +232,8 @@ class L2populationRpcCallBackTunnelMixin(L2populationRpcCallBackMixin,
vlan_manager = vlanmanager.LocalVlanManager() vlan_manager = vlanmanager.LocalVlanManager()
for network_id, values in fdb_entries.items(): for network_id, values in fdb_entries.items():
try: try:
lvm = vlan_manager.get(network_id) lvm = vlan_manager.get(
network_id, values.get('segment_id'))
except vlanmanager.MappingNotFound: except vlanmanager.MappingNotFound:
continue continue
agent_ports = values.get('ports') agent_ports = values.get('ports')
@ -307,22 +308,23 @@ class L2populationRpcCallBackTunnelMixin(L2populationRpcCallBackMixin,
vlan_manager = vlanmanager.LocalVlanManager() vlan_manager = vlanmanager.LocalVlanManager()
for network_id, agent_ports in fdb_entries.items(): for network_id, agent_ports in fdb_entries.items():
try: try:
lvm = vlan_manager.get(network_id) lvms = vlan_manager.get_segments(network_id)
except vlanmanager.MappingNotFound: except vlanmanager.MappingNotFound:
continue continue
for agent_ip, state in agent_ports.items(): for lvm in lvms.values():
if agent_ip == local_ip: for agent_ip, state in agent_ports.items():
continue if agent_ip == local_ip:
continue
after = state.get('after', []) after = state.get('after', [])
for mac_ip in after: for mac_ip in after:
self.setup_entry_for_arp_reply(br, 'add', lvm.vlan, self.setup_entry_for_arp_reply(br, 'add', lvm.vlan,
mac_ip.mac_address, mac_ip.mac_address,
mac_ip.ip_address) mac_ip.ip_address)
before = state.get('before', []) before = state.get('before', [])
for mac_ip in before: for mac_ip in before:
self.setup_entry_for_arp_reply(br, 'remove', lvm.vlan, self.setup_entry_for_arp_reply(br, 'remove', lvm.vlan,
mac_ip.mac_address, mac_ip.mac_address,
mac_ip.ip_address) mac_ip.ip_address)

View File

@ -490,15 +490,20 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
return return
try: try:
lvm = self.vlan_manager.get(network['id']) segmentation_id_old, lvm = (
except vlanmanager.MappingNotFound: self.vlan_manager.update_segmentation_id(
network['id'], network[provider_net.SEGMENTATION_ID]))
except vlanmanager.NotUniqMapping:
# There is a design issue, the RPC update network should not accept
# to update the segmentation id. We still support it if only one
# segment per network.
LOG.warning("Can't update segmentation id on no uniq segment "
"for a network %s", network['id'])
return return
segmentation_id_old = lvm.segmentation_id if segmentation_id_old is None:
if segmentation_id_old == network[provider_net.SEGMENTATION_ID]: # The segmentation id did not changed.
return return
self.vlan_manager.update_segmentation_id(
network['id'], network[provider_net.SEGMENTATION_ID])
lvid = lvm.vlan lvid = lvm.vlan
physical_network = network[provider_net.PHYSICAL_NETWORK] physical_network = network[provider_net.PHYSICAL_NETWORK]
@ -716,9 +721,9 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
def _add_network_ports(self, network_id, segmentation_id, port_id): def _add_network_ports(self, network_id, segmentation_id, port_id):
self.network_ports[network_id][segmentation_id].add(port_id) self.network_ports[network_id][segmentation_id].add(port_id)
def _get_net_local_vlan_or_none(self, net_id): def _get_net_local_vlan_or_none(self, net_id, segmentation_id):
try: try:
return self.vlan_manager.get(net_id).vlan return self.vlan_manager.get(net_id, segmentation_id).vlan
except vlanmanager.MappingNotFound: except vlanmanager.MappingNotFound:
return None return None
@ -982,22 +987,25 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
tags available. tags available.
""" """
try: try:
lvm = self.vlan_manager.get(net_uuid) lvm = self.vlan_manager.get(net_uuid, segmentation_id)
except vlanmanager.MappingNotFound: except vlanmanager.MappingNotFound:
lvid = self._local_vlan_hints.pop(net_uuid, None) lvid = self._local_vlan_hints.pop(net_uuid, None)
if lvid is None: if lvid is None:
if not self.available_local_vlans: if not self.available_local_vlans:
LOG.error("No local VLAN available for net-id=%s", LOG.error("No local VLAN available for net-id=%s, "
net_uuid) "seg-id=%s",
net_uuid, segmentation_id)
return return
lvid = self.available_local_vlans.pop() lvid = self.available_local_vlans.pop()
self.vlan_manager.add( self.vlan_manager.add(
net_uuid, lvid, network_type, physical_network, net_uuid, lvid, network_type, physical_network,
segmentation_id) segmentation_id)
lvm = self.vlan_manager.get(net_uuid) lvm = self.vlan_manager.get(net_uuid, segmentation_id)
LOG.info( LOG.info(
"Assigning %(vlan_id)s as local vlan for net-id=%(net_uuid)s", "Assigning %(vlan_id)s as local vlan for net-id=%(net_uuid)s, "
{'vlan_id': lvm.vlan, 'net_uuid': net_uuid}) "seg-id=%(seg_id)s",
{'vlan_id': lvm.vlan, 'net_uuid': net_uuid,
'seg_id': segmentation_id})
return lvm return lvm
@ -1067,20 +1075,23 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
{'network_type': network_type, {'network_type': network_type,
'net_uuid': net_uuid}) 'net_uuid': net_uuid})
def reclaim_local_vlan(self, net_uuid): def reclaim_local_vlan(self, net_uuid, segmentation_id):
'''Reclaim a local VLAN. '''Reclaim a local VLAN.
:param net_uuid: the network uuid associated with this vlan. :param net_uuid: the network uuid associated with this vlan.
''' '''
try: try:
lvm = vlanmanager.LocalVlanManager().pop(net_uuid) lvm = vlanmanager.LocalVlanManager().pop(
net_uuid, segmentation_id)
except vlanmanager.MappingNotFound: except vlanmanager.MappingNotFound:
LOG.debug("Network %s not used on agent.", net_uuid) LOG.debug("Network %s, for segmentation %s, not used on agent.",
net_uuid, segmentation_id)
return return
LOG.info("Reclaiming vlan = %(vlan_id)s from " LOG.info("Reclaiming vlan = %(vlan_id)s from "
"net-id = %(net_uuid)s", "net-id = %(net_uuid)s, seg-id = %(seg_id)s",
{'vlan_id': lvm.vlan, 'net_uuid': net_uuid}) {'vlan_id': lvm.vlan, 'net_uuid': net_uuid,
'seg_id': segmentation_id})
if lvm.network_type in ovs_const.TUNNEL_NETWORK_TYPES: if lvm.network_type in ovs_const.TUNNEL_NETWORK_TYPES:
if self.enable_tunneling: if self.enable_tunneling:
@ -1158,10 +1169,15 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
restart or recreated physical bridges restart or recreated physical bridges
and requires to do local vlan provisioning and requires to do local vlan provisioning
''' '''
if net_uuid not in self.vlan_manager or provisioning_needed: try:
lvm = self.vlan_manager.get(net_uuid, segmentation_id)
except vlanmanager.MappingNotFound:
lvm = None
if lvm is None or provisioning_needed:
self.provision_local_vlan(net_uuid, network_type, self.provision_local_vlan(net_uuid, network_type,
physical_network, segmentation_id) physical_network, segmentation_id)
lvm = self.vlan_manager.get(net_uuid) lvm = self.vlan_manager.get(net_uuid, segmentation_id)
lvm.vif_ports[port.vif_id] = port lvm.vif_ports[port.vif_id] = port
self.dvr_agent.bind_port_to_dvr(port, lvm, self.dvr_agent.bind_port_to_dvr(port, lvm,
@ -1201,7 +1217,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
tags_by_name = {x['name']: x['tag'] for x in port_info} tags_by_name = {x['name']: x['tag'] for x in port_info}
for port_detail in need_binding_ports: for port_detail in need_binding_ports:
try: try:
lvm = self.vlan_manager.get(port_detail['network_id']) lvm = self.vlan_manager.get(port_detail['network_id'],
port_detail['segmentation_id'])
except vlanmanager.MappingNotFound: except vlanmanager.MappingNotFound:
# network for port was deleted. skip this port since it # network for port was deleted. skip this port since it
# will need to be handled as a DEAD port in the next scan # will need to be handled as a DEAD port in the next scan
@ -1322,13 +1339,21 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
def _get_port_lvm_and_vif(self, vif_id, net_uuid=None): def _get_port_lvm_and_vif(self, vif_id, net_uuid=None):
try: try:
net_uuid = net_uuid or self.vlan_manager.get_net_uuid(vif_id) net_uuid, segmentation_id = (
self.vlan_manager.get_net_and_segmentation_id(
vif_id, net_uuid=net_uuid))
lvm = self.vlan_manager.get(net_uuid, segmentation_id)
except vlanmanager.VifIdNotFound: except vlanmanager.VifIdNotFound:
LOG.info('net_uuid %s not managed by VLAN manager', LOG.info('net_uuid %s not managed by VLAN manager',
net_uuid) net_uuid)
return None, None, None if net_uuid:
# TODO(sahid); This needs to be fixed. It supposes a segment
lvm = self.vlan_manager.get(net_uuid) # per network per host. Basically this code is to avoid
# changing logic which is not the aim of this commit.
segs = self.vlan_manager.get_segments(net_uuid)
lvm = self.vlan_manager.get(net_uuid, list(segs.keys())[0])
else:
return None, None, None
if vif_id in lvm.vif_ports: if vif_id in lvm.vif_ports:
vif_port = lvm.vif_ports[vif_id] vif_port = lvm.vif_ports[vif_id]
@ -1352,9 +1377,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
if vif_port and vif_id in lvm.vif_ports: if vif_port and vif_id in lvm.vif_ports:
self.dvr_agent.unbind_port_from_dvr(vif_port, lvm) self.dvr_agent.unbind_port_from_dvr(vif_port, lvm)
lvm.vif_ports.pop(vif_id, None) lvm.vif_ports.pop(vif_id, None)
if not lvm.vif_ports: if not lvm.vif_ports:
self.reclaim_local_vlan(net_uuid) self.reclaim_local_vlan(net_uuid, lvm.segmentation_id)
def port_alive(self, port, log_errors=True): def port_alive(self, port, log_errors=True):
cur_tag = self.int_br.db_get_val("Port", port.port_name, "tag", cur_tag = self.int_br.db_get_val("Port", port.port_name, "tag",
@ -1811,21 +1835,23 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
""" """
port_tags = self.int_br.get_port_tag_dict() port_tags = self.int_br.get_port_tag_dict()
changed_ports = set() changed_ports = set()
for lvm in self.vlan_manager: for vlan_mappings in self.vlan_manager:
for port in lvm.vif_ports.values(): for lvm in vlan_mappings.values():
if ( for port in lvm.vif_ports.values():
port.port_name in port_tags and if (
port_tags[port.port_name] != lvm.vlan port.port_name in port_tags and
): port_tags[port.port_name] != lvm.vlan
LOG.info( ):
"Port '%(port_name)s' has lost " LOG.info(
"its vlan tag '%(vlan_tag)d'! " "Port '%(port_name)s' has lost "
"Current vlan tag on this port is '%(new_vlan_tag)s'.", "its vlan tag '%(vlan_tag)d'! "
{'port_name': port.port_name, "Current vlan tag on this port is "
'vlan_tag': lvm.vlan, "'%(new_vlan_tag)s'.",
'new_vlan_tag': port_tags[port.port_name]} {'port_name': port.port_name,
) 'vlan_tag': lvm.vlan,
changed_ports.add(port.vif_id) 'new_vlan_tag': port_tags[port.port_name]}
)
changed_ports.add(port.vif_id)
if changed_ports: if changed_ports:
# explicitly mark these DOWN on the server since they have been # explicitly mark these DOWN on the server since they have been
# manipulated (likely a nova unplug/replug) and need to be rewired # manipulated (likely a nova unplug/replug) and need to be rewired
@ -1906,11 +1932,12 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
ofports = self.tun_br_ofports[tunnel_type].values() ofports = self.tun_br_ofports[tunnel_type].values()
if ofports and not self.l2_pop: if ofports and not self.l2_pop:
# Update flooding flows to include the new tunnel # Update flooding flows to include the new tunnel
for vlan_mapping in self.vlan_manager: for vlan_mappings in self.vlan_manager:
if vlan_mapping.network_type == tunnel_type: for vlan_mapping in vlan_mappings.values():
br.install_flood_to_tun(vlan_mapping.vlan, if vlan_mapping.network_type == tunnel_type:
vlan_mapping.segmentation_id, br.install_flood_to_tun(vlan_mapping.vlan,
ofports) vlan_mapping.segmentation_id,
ofports)
def setup_tunnel_port(self, br, remote_ip, network_type): def setup_tunnel_port(self, br, remote_ip, network_type):
port_name = self.get_tunnel_name( port_name = self.get_tunnel_name(
@ -1926,19 +1953,21 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
def cleanup_tunnel_port(self, br, tun_ofport, tunnel_type): def cleanup_tunnel_port(self, br, tun_ofport, tunnel_type):
# Check if this tunnel port is still used # Check if this tunnel port is still used
for lvm in self.vlan_manager: for vlan_mappings in self.vlan_manager:
if tun_ofport in lvm.tun_ofports: for lvm in vlan_mappings.values():
break if tun_ofport in lvm.tun_ofports:
# still used
return
# If not, remove it # If not, remove it
else: items = list(self.tun_br_ofports[tunnel_type].items())
items = list(self.tun_br_ofports[tunnel_type].items()) for remote_ip, ofport in items:
for remote_ip, ofport in items: if ofport == tun_ofport:
if ofport == tun_ofport: port_name = self.get_tunnel_name(
port_name = self.get_tunnel_name( tunnel_type, self.local_ip, remote_ip)
tunnel_type, self.local_ip, remote_ip) br.delete_port(port_name)
br.delete_port(port_name) br.cleanup_tunnel_port(ofport)
br.cleanup_tunnel_port(ofport) self.tun_br_ofports[tunnel_type].pop(
self.tun_br_ofports[tunnel_type].pop(remote_ip, None) remote_ip, None)
def treat_devices_added_or_updated(self, devices, provisioning_needed, def treat_devices_added_or_updated(self, devices, provisioning_needed,
re_added): re_added):
@ -1984,7 +2013,7 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
if 'port_id' in details: if 'port_id' in details:
details['vif_port'] = port details['vif_port'] = port
details['local_vlan'] = self._get_net_local_vlan_or_none( details['local_vlan'] = self._get_net_local_vlan_or_none(
details['network_id']) details['network_id'], details['segmentation_id'])
LOG.info("Port %(device)s updated. Details: %(details)s", LOG.info("Port %(device)s updated. Details: %(details)s",
{'device': device, 'details': details}) {'device': device, 'details': details})
need_binding = self.treat_vif_port(port, details['port_id'], need_binding = self.treat_vif_port(port, details['port_id'],
@ -2233,7 +2262,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
if self.enable_local_ips and port['device_owner'].startswith( if self.enable_local_ips and port['device_owner'].startswith(
n_const.DEVICE_OWNER_COMPUTE_PREFIX): n_const.DEVICE_OWNER_COMPUTE_PREFIX):
try: try:
lvm = self.vlan_manager.get(port['network_id']) lvm = self.vlan_manager.get(
port['network_id'], port['segmentation_id'])
self.int_br.setup_local_egress_flows( self.int_br.setup_local_egress_flows(
port['vif_port'].ofport, lvm.vlan) port['vif_port'].ofport, lvm.vlan)
except Exception as err: except Exception as err:
@ -2250,7 +2280,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
port['port_id'], err) port['port_id'], err)
def install_accepted_egress_direct_flow(self, port_detail, br_int): def install_accepted_egress_direct_flow(self, port_detail, br_int):
lvm = self.vlan_manager.get(port_detail['network_id']) lvm = self.vlan_manager.get(
port_detail['network_id'], port_detail['segmentation_id'])
port = port_detail['vif_port'] port = port_detail['vif_port']
# Adding the local vlan to register 6 in case of MAC overlapping # Adding the local vlan to register 6 in case of MAC overlapping

View File

@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from collections import defaultdict
from neutron_lib import exceptions from neutron_lib import exceptions
from neutron._i18n import _ from neutron._i18n import _
@ -24,11 +26,17 @@ class VifIdNotFound(exceptions.NeutronException):
class MappingAlreadyExists(exceptions.NeutronException): class MappingAlreadyExists(exceptions.NeutronException):
message = _('VLAN mapping for network with id %(net_id)s already exists') message = _('VLAN mapping for network with id %(net_id)s and '
'segmentation id %(seg_id)s already exists')
class MappingNotFound(exceptions.NeutronException): class MappingNotFound(exceptions.NeutronException):
message = _('Mapping for network %(net_id)s not found.') message = _('Mapping VLAN for network %(net_id)s with segmentation id '
'%(seg_id)s not found.')
class NotUniqMapping(exceptions.NeutronException):
message = _('Mapping VLAN for network %(net_id)s should be unique.')
class LocalVLANMapping(object): class LocalVLANMapping(object):
@ -71,7 +79,7 @@ class LocalVlanManager(object):
def __init__(self): def __init__(self):
if not hasattr(self, 'mapping'): if not hasattr(self, 'mapping'):
self.mapping = {} self.mapping = defaultdict(dict)
def __contains__(self, key): def __contains__(self, key):
return key in self.mapping return key in self.mapping
@ -86,31 +94,55 @@ class LocalVlanManager(object):
def add(self, net_id, vlan, network_type, physical_network, def add(self, net_id, vlan, network_type, physical_network,
segmentation_id, vif_ports=None): segmentation_id, vif_ports=None):
if net_id in self.mapping: try:
raise MappingAlreadyExists(net_id=net_id) if self.get(net_id, segmentation_id):
self.mapping[net_id] = LocalVLANMapping( raise MappingAlreadyExists(
net_id=net_id, seg_id=segmentation_id)
except MappingNotFound:
pass
self.mapping[net_id][segmentation_id] = LocalVLANMapping(
vlan, network_type, physical_network, segmentation_id, vif_ports) vlan, network_type, physical_network, segmentation_id, vif_ports)
def get_net_uuid(self, vif_id): def get_net_and_segmentation_id(self, vif_id, net_uuid=None):
for network_id, vlan_mapping in self.mapping.items(): # TODO(sahid): We should improve algorithm if net_uuid is passed.
if vif_id in vlan_mapping.vif_ports: for network_id, vlan_mappings in self.mapping.items():
return network_id for segmentation_id, vlan_mapping in vlan_mappings.items():
if vif_id in vlan_mapping.vif_ports:
return network_id, segmentation_id
raise VifIdNotFound(vif_id=vif_id) raise VifIdNotFound(vif_id=vif_id)
def get(self, net_id): def get(self, net_id, segmentation_id):
try: if net_id in self.mapping and segmentation_id in self.mapping[net_id]:
return self.mapping[net_id] return self.mapping[net_id][segmentation_id]
except KeyError: raise MappingNotFound(net_id=net_id, seg_id=segmentation_id)
raise MappingNotFound(net_id=net_id)
def pop(self, net_id): def get_segments(self, net_id):
try: if net_id not in self.mapping:
return self.mapping.pop(net_id) raise MappingNotFound(net_id=net_id, seg_id="<all>")
except KeyError: return self.mapping[net_id]
raise MappingNotFound(net_id=net_id)
def pop(self, net_id, segmentation_id):
if self.get(net_id, segmentation_id):
ret = self.mapping[net_id].pop(segmentation_id)
# if it's the last seg id for a network, let's removed the network
# entry as-well.
if len(self.mapping[net_id]) == 0:
del self.mapping[net_id]
return ret
def update_segmentation_id(self, net_id, segmentation_id): def update_segmentation_id(self, net_id, segmentation_id):
try: """Returns tuple with segmentation id, lvm in success or None, None"""
self.mapping[net_id].segmentation_id = segmentation_id if len(self.get_segments(net_id)) != 1:
except KeyError: # Update of segmentation id can work only if network has one
raise MappingNotFound(net_id=net_id) # segment. This is a design issue that should be fixed in
# future. We should not accept segmentation update for a network.
raise NotUniqMapping(net_id=net_id)
mapping = list(self.mapping[net_id].values())[0]
if mapping.segmentation_id == segmentation_id:
# No need to update
return None, None
old = mapping.segmentation_id
del self.mapping[net_id][old]
mapping.segmentation_id = segmentation_id
self.mapping[net_id][segmentation_id] = mapping
return old, mapping

View File

@ -120,7 +120,8 @@ class TestL2populationRpcCallBackTunnelMixinBase(base.BaseTestCase):
self.lvms[i].vlan, self.type_gre, self.lvms[i].phys, self.lvms[i].vlan, self.type_gre, self.lvms[i].phys,
self.lvms[i].segid, {self.lvms[i].vif: self.lvms[i].port}) self.lvms[i].segid, {self.lvms[i].vif: self.lvms[i].port})
setattr(self, 'lvm%d' % i, setattr(self, 'lvm%d' % i,
self.vlan_manager.get(self.lvms[i].net)) self.vlan_manager.get(
self.lvms[i].net, self.lvms[i].segid))
self.upd_fdb_entry1_val = { self.upd_fdb_entry1_val = {
self.lvms[0].net: { self.lvms[0].net: {

View File

@ -33,7 +33,7 @@ class TestL2populationRpcCallBackTunnelMixin(
def test_get_agent_ports_non_existence_key_in_lvm(self): def test_get_agent_ports_non_existence_key_in_lvm(self):
results = {} results = {}
self.vlan_manager.pop(self.lvms[1].net) self.vlan_manager.pop(self.lvms[1].net, self.lvms[1].segid)
for lvm, agent_ports in self.fakeagent.get_agent_ports( for lvm, agent_ports in self.fakeagent.get_agent_ports(
self.fdb_entries1): self.fdb_entries1):
results[lvm] = agent_ports results[lvm] = agent_ports

View File

@ -69,8 +69,10 @@ TEST_PORT_ID3 = 'port-id-3'
TEST_NETWORK_ID1 = 'net-id-1' TEST_NETWORK_ID1 = 'net-id-1'
TEST_NETWORK_ID2 = 'net-id-2' TEST_NETWORK_ID2 = 'net-id-2'
TEST_SEGMENTATION_ID1 = 'seg-id-1' # Currently it's only accepted to have one segmentation per network. In future
TEST_SEGMENTATION_ID2 = 'seg-id-2' # we will accept more.
TEST_SEG_NET1_ID1 = 'net-id-1-seg-id-1'
TEST_SEG_NET2_ID1 = 'net-id-2-seg-id-1'
TEST_MTU = 7824 TEST_MTU = 7824
@ -189,7 +191,7 @@ class TestOvsNeutronAgent(object):
int_br.db_get_val.return_value = db_get_val int_br.db_get_val.return_value = db_get_val
int_br.set_db_attribute.return_value = True int_br.set_db_attribute.return_value = True
needs_binding = self.agent.port_bound( needs_binding = self.agent.port_bound(
port, net_uuid, 'local', None, None, port, net_uuid, 'local', None, 'seg1',
fixed_ips, DEVICE_OWNER_COMPUTE, False) fixed_ips, DEVICE_OWNER_COMPUTE, False)
if db_get_val is None: if db_get_val is None:
int_br.assert_not_called() int_br.assert_not_called()
@ -198,6 +200,7 @@ class TestOvsNeutronAgent(object):
vlan_mapping = {'net_uuid': net_uuid, vlan_mapping = {'net_uuid': net_uuid,
'network_type': 'local', 'network_type': 'local',
'physical_network': 'None', 'physical_network': 'None',
'segmentation_id': 'seg1',
'tag': str(new_local_vlan)} 'tag': str(new_local_vlan)}
set_vlan.assert_called_once_with(port, new_local_vlan) set_vlan.assert_called_once_with(port, new_local_vlan)
int_br.set_db_attribute.assert_called_once_with( int_br.set_db_attribute.assert_called_once_with(
@ -700,7 +703,7 @@ class TestOvsNeutronAgent(object):
def test_bind_devices(self): def test_bind_devices(self):
devices_up = ['tap1'] devices_up = ['tap1']
devices_down = ['tap2'] devices_down = ['tap2']
self.agent.vlan_manager.mapping["net1"] = mock.Mock() self.agent.vlan_manager.mapping["net1"]['seg1'] = mock.Mock()
ovs_db_list = [{'name': 'tap1', 'tag': []}, ovs_db_list = [{'name': 'tap1', 'tag': []},
{'name': 'tap2', 'tag': []}] {'name': 'tap2', 'tag': []}]
vif_port1 = mock.Mock() vif_port1 = mock.Mock()
@ -709,10 +712,12 @@ class TestOvsNeutronAgent(object):
vif_port2.port_name = 'tap2' vif_port2.port_name = 'tap2'
port_details = [ port_details = [
{'network_id': 'net1', 'vif_port': vif_port1, {'network_id': 'net1', 'vif_port': vif_port1,
'segmentation_id': 'seg1',
'device': devices_up[0], 'device': devices_up[0],
'device_owner': 'network:dhcp', 'device_owner': 'network:dhcp',
'admin_state_up': True}, 'admin_state_up': True},
{'network_id': 'net1', 'vif_port': vif_port2, {'network_id': 'net1', 'vif_port': vif_port2,
'segmentation_id': 'seg1',
'device': devices_down[0], 'device': devices_down[0],
'device_owner': 'network:dhcp', 'device_owner': 'network:dhcp',
'admin_state_up': False}] 'admin_state_up': False}]
@ -737,11 +742,13 @@ class TestOvsNeutronAgent(object):
self.agent.vlan_manager.add('fake_network', 1, self.agent.vlan_manager.add('fake_network', 1,
n_const.TYPE_VXLAN, None, 1) n_const.TYPE_VXLAN, None, 1)
ovs_db_list = [{'name': 'fake_device', 'tag': []}] ovs_db_list = [{'name': 'fake_device', 'tag': []}]
self.agent.vlan_manager.get('fake_network').tun_ofports = tun_ofports self.agent.vlan_manager.get(
'fake_network', 1).tun_ofports = tun_ofports
vif_port = mock.Mock() vif_port = mock.Mock()
vif_port.port_name = 'fake_device' vif_port.port_name = 'fake_device'
vif_port.ofport = 1 vif_port.ofport = 1
need_binding_ports = [{'network_id': 'fake_network', need_binding_ports = [{'network_id': 'fake_network',
'segmentation_id': 1,
'vif_port': vif_port, 'vif_port': vif_port,
'device': 'fake_device', 'device': 'fake_device',
'admin_state_up': True}] 'admin_state_up': True}]
@ -774,6 +781,7 @@ class TestOvsNeutronAgent(object):
vif_port.port_name = 'fake_device' vif_port.port_name = 'fake_device'
vif_port.ofport = 1 vif_port.ofport = 1
need_binding_ports = [{'network_id': 'fake_network', need_binding_ports = [{'network_id': 'fake_network',
'segmentation_id': 1,
'vif_port': vif_port, 'vif_port': vif_port,
'device': 'fake_device', 'device': 'fake_device',
'admin_state_up': True}] 'admin_state_up': True}]
@ -1093,6 +1101,7 @@ class TestOvsNeutronAgent(object):
vif_port = mock.Mock() vif_port = mock.Mock()
vif_port.name.return_value = 'port' vif_port.name.return_value = 'port'
self.agent._bind_devices([{'network_id': 'non-existent', self.agent._bind_devices([{'network_id': 'non-existent',
'segmentation_id': 'seg1',
'vif_port': vif_port}]) 'vif_port': vif_port}])
def _test_process_network_ports(self, port_info, skipped_devices=None, def _test_process_network_ports(self, port_info, skipped_devices=None,
@ -1398,7 +1407,7 @@ class TestOvsNeutronAgent(object):
def test_process_deleted_ports_cleans_network_ports(self): def test_process_deleted_ports_cleans_network_ports(self):
self.agent._update_port_network( self.agent._update_port_network(
TEST_PORT_ID1, TEST_NETWORK_ID1, TEST_SEGMENTATION_ID1) TEST_PORT_ID1, TEST_NETWORK_ID1, TEST_SEG_NET1_ID1)
self.agent.port_delete(context=None, port_id=TEST_PORT_ID1) self.agent.port_delete(context=None, port_id=TEST_PORT_ID1)
self.agent.sg_agent = mock.Mock() self.agent.sg_agent = mock.Mock()
self.agent.int_br = mock.Mock() self.agent.int_br = mock.Mock()
@ -1411,7 +1420,7 @@ class TestOvsNeutronAgent(object):
self.agent.process_deleted_ports(port_info={}) self.agent.process_deleted_ports(port_info={})
self.assertEqual( self.assertEqual(
set(), self.agent.network_ports[ set(), self.agent.network_ports[
TEST_NETWORK_ID1][TEST_SEGMENTATION_ID1]) TEST_NETWORK_ID1][TEST_SEG_NET1_ID1])
def test_network_update(self): def test_network_update(self):
"""Network update marks port for update. """ """Network update marks port for update. """
@ -1419,7 +1428,7 @@ class TestOvsNeutronAgent(object):
port = {'id': TEST_PORT_ID1, 'network_id': network['id']} port = {'id': TEST_PORT_ID1, 'network_id': network['id']}
self.agent._update_port_network( self.agent._update_port_network(
port['id'], port['network_id'], TEST_SEGMENTATION_ID1) port['id'], port['network_id'], TEST_SEG_NET1_ID1)
with mock.patch.object(self.agent.plugin_rpc, 'get_network_details'), \ with mock.patch.object(self.agent.plugin_rpc, 'get_network_details'), \
mock.patch.object(self.agent, mock.patch.object(self.agent,
'_update_network_segmentation_id'): '_update_network_segmentation_id'):
@ -1436,7 +1445,7 @@ class TestOvsNeutronAgent(object):
port = {'id': TEST_PORT_ID1, 'network_id': network['id']} port = {'id': TEST_PORT_ID1, 'network_id': network['id']}
self.agent._update_port_network( self.agent._update_port_network(
port['id'], port['network_id'], TEST_SEGMENTATION_ID1) port['id'], port['network_id'], TEST_SEG_NET1_ID1)
self.agent.port_delete(context=None, port_id=port['id']) self.agent.port_delete(context=None, port_id=port['id'])
with mock.patch.object(self.agent.plugin_rpc, 'get_network_details'), \ with mock.patch.object(self.agent.plugin_rpc, 'get_network_details'), \
mock.patch.object(self.agent, mock.patch.object(self.agent,
@ -1447,20 +1456,20 @@ class TestOvsNeutronAgent(object):
def test_update_port_network(self): def test_update_port_network(self):
"""Ensure ports are associated and moved across networks correctly.""" """Ensure ports are associated and moved across networks correctly."""
self.agent._update_port_network( self.agent._update_port_network(
TEST_PORT_ID1, TEST_NETWORK_ID1, TEST_SEGMENTATION_ID1) TEST_PORT_ID1, TEST_NETWORK_ID1, TEST_SEG_NET1_ID1)
self.agent._update_port_network( self.agent._update_port_network(
TEST_PORT_ID2, TEST_NETWORK_ID1, TEST_SEGMENTATION_ID2) TEST_PORT_ID2, TEST_NETWORK_ID1, TEST_SEG_NET1_ID1)
self.agent._update_port_network( self.agent._update_port_network(
TEST_PORT_ID3, TEST_NETWORK_ID2, TEST_SEGMENTATION_ID1) TEST_PORT_ID3, TEST_NETWORK_ID2, TEST_SEG_NET2_ID1)
self.agent._update_port_network( self.agent._update_port_network(
TEST_PORT_ID1, TEST_NETWORK_ID2, TEST_SEGMENTATION_ID1) TEST_PORT_ID1, TEST_NETWORK_ID2, TEST_SEG_NET2_ID1)
self.assertEqual(set([TEST_PORT_ID2]), self.assertEqual(set([TEST_PORT_ID2]),
self.agent.network_ports[TEST_NETWORK_ID1][ self.agent.network_ports[TEST_NETWORK_ID1][
TEST_SEGMENTATION_ID2]) TEST_SEG_NET1_ID1])
self.assertEqual(set([TEST_PORT_ID1, TEST_PORT_ID3]), self.assertEqual(set([TEST_PORT_ID1, TEST_PORT_ID3]),
self.agent.network_ports[TEST_NETWORK_ID2][ self.agent.network_ports[TEST_NETWORK_ID2][
TEST_SEGMENTATION_ID1]) TEST_SEG_NET2_ID1])
def test_port_delete(self): def test_port_delete(self):
vif = FakeVif() vif = FakeVif()
@ -1802,9 +1811,11 @@ class TestOvsNeutronAgent(object):
with mock.patch.object(self.agent, "reclaim_local_vlan") as reclvl_fn: with mock.patch.object(self.agent, "reclaim_local_vlan") as reclvl_fn:
self.agent.enable_tunneling = True self.agent.enable_tunneling = True
lvm = mock.Mock() lvm = mock.Mock()
lvm.network_id = "netuid12345"
lvm.segmentation_id = "seg1"
lvm.network_type = "gre" lvm.network_type = "gre"
lvm.vif_ports = {"vif1": mock.Mock()} lvm.vif_ports = {"vif1": mock.Mock()}
self.agent.vlan_manager.mapping["netuid12345"] = lvm self.agent.vlan_manager.mapping["netuid12345"]['seg1'] = lvm
self.agent.port_unbound("vif1", "netuid12345") self.agent.port_unbound("vif1", "netuid12345")
self.assertTrue(reclvl_fn.called) self.assertTrue(reclvl_fn.called)
@ -1827,7 +1838,8 @@ class TestOvsNeutronAgent(object):
lvm2.vlan = 'vlan2' lvm2.vlan = 'vlan2'
lvm2.segmentation_id = 'seg2' lvm2.segmentation_id = 'seg2'
lvm2.tun_ofports = set(['1', '2']) lvm2.tun_ofports = set(['1', '2'])
self.agent.vlan_manager.mapping = {'net1': lvm1, 'net2': lvm2} self.agent.vlan_manager.mapping = {'net1': {"seg1": lvm1},
'net2': {"seg2": lvm2}}
self.agent.tun_br_ofports = {'gre': self.agent.tun_br_ofports = {'gre':
{'1.1.1.1': '1', '2.2.2.2': '2'}} {'1.1.1.1': '1', '2.2.2.2': '2'}}
self.agent.arp_responder_enabled = True self.agent.arp_responder_enabled = True
@ -1870,7 +1882,7 @@ class TestOvsNeutronAgent(object):
self._prepare_l2_pop_ofports() self._prepare_l2_pop_ofports()
fdb_entry = {'net1': fdb_entry = {'net1':
{'network_type': 'gre', {'network_type': 'gre',
'segment_id': 'tun1', 'segment_id': 'seg1',
'ports': 'ports':
{'2.2.2.2': {'2.2.2.2':
[l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1), [l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1),
@ -1895,7 +1907,7 @@ class TestOvsNeutronAgent(object):
self._prepare_l2_pop_ofports() self._prepare_l2_pop_ofports()
fdb_entry = {'net2': fdb_entry = {'net2':
{'network_type': 'gre', {'network_type': 'gre',
'segment_id': 'tun2', 'segment_id': 'seg2',
'ports': 'ports':
{'2.2.2.2': {'2.2.2.2':
[l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1), [l2pop_rpc.PortInfo(FAKE_MAC, FAKE_IP1),
@ -1915,7 +1927,7 @@ class TestOvsNeutronAgent(object):
self._prepare_l2_pop_ofports() self._prepare_l2_pop_ofports()
fdb_entry = {'net1': fdb_entry = {'net1':
{'network_type': 'gre', {'network_type': 'gre',
'segment_id': 'tun1', 'segment_id': 'seg1',
'ports': {'1.1.1.1': [l2pop_rpc.PortInfo(FAKE_MAC, 'ports': {'1.1.1.1': [l2pop_rpc.PortInfo(FAKE_MAC,
FAKE_IP1)]}}} FAKE_IP1)]}}}
with mock.patch.object(self.agent, 'tun_br', autospec=True) as tun_br,\ with mock.patch.object(self.agent, 'tun_br', autospec=True) as tun_br,\
@ -1933,7 +1945,7 @@ class TestOvsNeutronAgent(object):
self._prepare_l2_pop_ofports() self._prepare_l2_pop_ofports()
fdb_entry = {'net2': fdb_entry = {'net2':
{'network_type': 'gre', {'network_type': 'gre',
'segment_id': 'tun2', 'segment_id': 'seg2',
'ports': {'2.2.2.2': [n_const.FLOODING_ENTRY]}}} 'ports': {'2.2.2.2': [n_const.FLOODING_ENTRY]}}}
with mock.patch.object(self.agent, 'tun_br', autospec=True) as tun_br: with mock.patch.object(self.agent, 'tun_br', autospec=True) as tun_br:
self.agent.fdb_remove(None, fdb_entry) self.agent.fdb_remove(None, fdb_entry)
@ -1972,22 +1984,21 @@ class TestOvsNeutronAgent(object):
self.agent.l2_pop = True self.agent.l2_pop = True
self.agent.enable_tunneling = True self.agent.enable_tunneling = True
with mock.patch.object(self.agent, 'tun_br', autospec=True) as tun_br: with mock.patch.object(self.agent, 'tun_br', autospec=True) as tun_br:
self.agent.reclaim_local_vlan('net1') self.agent.reclaim_local_vlan('net1', 'seg1')
tun_br.cleanup_tunnel_port.assert_not_called() tun_br.cleanup_tunnel_port.assert_not_called()
with mock.patch.object(self.mod_agent.LOG, 'debug') as log_debug_fn: with mock.patch.object(self.mod_agent.LOG, 'debug') as log_debug_fn:
self.agent.reclaim_local_vlan('net999') self.agent.reclaim_local_vlan('net999', 'seg999')
log_debug_fn.assert_called_once_with( log_debug_fn.assert_called_once_with(
'Network %s not used on agent.', 'Network %s, for segmentation %s, not used on agent.',
'net999', 'net999', 'seg999')
)
def test_recl_lv_port_to_remove(self): def test_recl_lv_port_to_remove(self):
self._prepare_l2_pop_ofports() self._prepare_l2_pop_ofports()
self.agent.l2_pop = True self.agent.l2_pop = True
self.agent.enable_tunneling = True self.agent.enable_tunneling = True
with mock.patch.object(self.agent, 'tun_br', autospec=True) as tun_br: with mock.patch.object(self.agent, 'tun_br', autospec=True) as tun_br:
self.agent.reclaim_local_vlan('net2') self.agent.reclaim_local_vlan('net2', 'seg2')
tun_br.delete_port.assert_called_once_with('gre-02020202') tun_br.delete_port.assert_called_once_with('gre-02020202')
def _test_ext_br_recreated(self, setup_bridges_side_effect): def _test_ext_br_recreated(self, setup_bridges_side_effect):
@ -2671,9 +2682,10 @@ class TestOvsNeutronAgent(object):
provider_net.NETWORK_TYPE: n_const.TYPE_VLAN, provider_net.NETWORK_TYPE: n_const.TYPE_VLAN,
provider_net.PHYSICAL_NETWORK: 'default_network'} provider_net.PHYSICAL_NETWORK: 'default_network'}
with mock.patch.object(self.agent.vlan_manager, with mock.patch.object(self.agent.vlan_manager,
'update_segmentation_id') as mock_update_segid: 'update_segmentation_id',
return_value=(None, None)) as mock_update_segid:
self.agent._update_network_segmentation_id(network) self.agent._update_network_segmentation_id(network)
mock_update_segid.assert_not_called() mock_update_segid.assert_called_once_with('my-net-uuid', 1005)
def test__update_network_segmentation_id_segmentation_id_not_updated(self): def test__update_network_segmentation_id_segmentation_id_not_updated(self):
network = {'id': 'my-net-uuid', network = {'id': 'my-net-uuid',
@ -2683,9 +2695,10 @@ class TestOvsNeutronAgent(object):
self.agent.vlan_manager.add('my-net-uuid', 5, n_const.TYPE_VLAN, self.agent.vlan_manager.add('my-net-uuid', 5, n_const.TYPE_VLAN,
'provider_net', 1005, None) 'provider_net', 1005, None)
with mock.patch.object(self.agent.vlan_manager, with mock.patch.object(self.agent.vlan_manager,
'update_segmentation_id') as mock_update_segid: 'update_segmentation_id',
return_value=(None, None)) as mock_update_segid:
self.agent._update_network_segmentation_id(network) self.agent._update_network_segmentation_id(network)
mock_update_segid.assert_not_called() mock_update_segid.assert_called_once_with('my-net-uuid', 1005)
def test__update_network_segmentation_id_multisegments(self): def test__update_network_segmentation_id_multisegments(self):
network = {'id': 'my-net-uuid', network = {'id': 'my-net-uuid',
@ -3232,7 +3245,8 @@ class TestOvsDvrNeutronAgent(object):
n_const.DEVICE_OWNER_DVR_INTERFACE, False) n_const.DEVICE_OWNER_DVR_INTERFACE, False)
phy_ofp = self.agent.dvr_agent.phys_ofports[physical_network] phy_ofp = self.agent.dvr_agent.phys_ofports[physical_network]
int_ofp = self.agent.dvr_agent.int_ofports[physical_network] int_ofp = self.agent.dvr_agent.int_ofports[physical_network]
lvid = self.agent.vlan_manager.get(self._net_uuid).vlan lvid = self.agent.vlan_manager.get(
self._net_uuid, segmentation_id).vlan
expected_on_phys_br = [ expected_on_phys_br = [
mock.call.provision_local_vlan( mock.call.provision_local_vlan(
port=phy_ofp, port=phy_ofp,
@ -3329,7 +3343,8 @@ class TestOvsDvrNeutronAgent(object):
self._port, self._net_uuid, network_type, self._port, self._net_uuid, network_type,
physical_network, segmentation_id, self._fixed_ips, physical_network, segmentation_id, self._fixed_ips,
n_const.DEVICE_OWNER_DVR_INTERFACE, False) n_const.DEVICE_OWNER_DVR_INTERFACE, False)
lvid = self.agent.vlan_manager.get(self._net_uuid).vlan lvid = self.agent.vlan_manager.get(
self._net_uuid, self._segmentation_id).vlan
expected_on_int_br = self._expected_port_bound( expected_on_int_br = self._expected_port_bound(
self._port, lvid) self._port, lvid)
if ip_version == n_const.IP_VERSION_4: if ip_version == n_const.IP_VERSION_4:
@ -3418,7 +3433,8 @@ class TestOvsDvrNeutronAgent(object):
def test_port_bound_for_dvr_with_csnat_ports(self): def test_port_bound_for_dvr_with_csnat_ports(self):
self._setup_for_dvr_test() self._setup_for_dvr_test()
int_br, tun_br = self._port_bound_for_dvr_with_csnat_ports() int_br, tun_br = self._port_bound_for_dvr_with_csnat_ports()
lvid = self.agent.vlan_manager.get(self._net_uuid).vlan lvid = self.agent.vlan_manager.get(
self._net_uuid, self._segmentation_id).vlan
expected_on_int_br = [ expected_on_int_br = [
mock.call.install_dvr_to_src_mac( mock.call.install_dvr_to_src_mac(
network_type='vxlan', network_type='vxlan',
@ -3433,7 +3449,7 @@ class TestOvsDvrNeutronAgent(object):
mock.call.provision_local_vlan( mock.call.provision_local_vlan(
network_type='vxlan', network_type='vxlan',
lvid=lvid, lvid=lvid,
segmentation_id=None, segmentation_id=self._segmentation_id,
distributed=True, distributed=True,
), ),
] ]
@ -3471,7 +3487,8 @@ class TestOvsDvrNeutronAgent(object):
# simulate a replug # simulate a replug
self._port.ofport = 12 self._port.ofport = 12
int_br, tun_br = self._port_bound_for_dvr_with_csnat_ports() int_br, tun_br = self._port_bound_for_dvr_with_csnat_ports()
lvid = self.agent.vlan_manager.get(self._net_uuid).vlan lvid = self.agent.vlan_manager.get(
self._net_uuid, self._segmentation_id).vlan
expected_on_int_br = [ expected_on_int_br = [
mock.call.delete_dvr_to_src_mac( mock.call.delete_dvr_to_src_mac(
network_type='vxlan', network_type='vxlan',
@ -3517,7 +3534,7 @@ class TestOvsDvrNeutronAgent(object):
mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br): mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br):
self.agent.port_bound( self.agent.port_bound(
self._port, self._net_uuid, 'vxlan', self._port, self._net_uuid, 'vxlan',
None, None, self._fixed_ips, None, self._segmentation_id, self._fixed_ips,
n_const.DEVICE_OWNER_ROUTER_SNAT, n_const.DEVICE_OWNER_ROUTER_SNAT,
False) False)
return int_br, tun_br return int_br, tun_br
@ -3537,7 +3554,7 @@ class TestOvsDvrNeutronAgent(object):
mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br): mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br):
self.agent.port_bound( self.agent.port_bound(
self._port, self._net_uuid, 'vxlan', self._port, self._net_uuid, 'vxlan',
None, None, self._fixed_ips, None, self._segmentation_id, self._fixed_ips,
n_const.DEVICE_OWNER_ROUTER_SNAT, n_const.DEVICE_OWNER_ROUTER_SNAT,
False) False)
int_br.install_dvr_to_src_mac.assert_not_called() int_br.install_dvr_to_src_mac.assert_not_called()
@ -3603,7 +3620,8 @@ class TestOvsDvrNeutronAgent(object):
physical_network, segmentation_id, self._fixed_ips, physical_network, segmentation_id, self._fixed_ips,
n_const.DEVICE_OWNER_DVR_INTERFACE, False) n_const.DEVICE_OWNER_DVR_INTERFACE, False)
lvid = self.agent.vlan_manager.get(self._net_uuid).vlan lvid = self.agent.vlan_manager.get(
self._net_uuid, self._segmentation_id).vlan
# Bound non-gateway port # Bound non-gateway port
self.agent.port_bound( self.agent.port_bound(
@ -3751,16 +3769,19 @@ class TestOvsDvrNeutronAgent(object):
else: else:
self.agent.port_bound( self.agent.port_bound(
self._port, self._net_uuid, 'vxlan', self._port, self._net_uuid, 'vxlan',
None, None, self._fixed_ips, None, self._segmentation_id, self._fixed_ips,
n_const.DEVICE_OWNER_DVR_INTERFACE, n_const.DEVICE_OWNER_DVR_INTERFACE,
False) False)
lvid = self.agent.vlan_manager.get(self._net_uuid).vlan lvid = self.agent.vlan_manager.get(
self._net_uuid, self._segmentation_id).vlan
int_br.assert_has_calls( int_br.assert_has_calls(
self._expected_port_bound(self._port, lvid), self._expected_port_bound(self._port, lvid),
any_order=True) any_order=True)
expected_on_tun_br = [ expected_on_tun_br = [
mock.call.provision_local_vlan(network_type='vxlan', mock.call.provision_local_vlan(
lvid=lvid, segmentation_id=None, distributed=True), network_type='vxlan',
lvid=lvid, segmentation_id=self._segmentation_id,
distributed=True),
] + self._expected_install_dvr_process( ] + self._expected_install_dvr_process(
port=self._port, port=self._port,
lvid=lvid, lvid=lvid,
@ -3792,7 +3813,8 @@ class TestOvsDvrNeutronAgent(object):
failed_devices = {'added': set(), 'removed': set()} failed_devices = {'added': set(), 'removed': set()}
failed_devices['removed'] = self.agent.treat_devices_removed( failed_devices['removed'] = self.agent.treat_devices_removed(
[self._port.vif_id]) [self._port.vif_id])
lvid = self.agent.vlan_manager.get(self._net_uuid).vlan lvid = self.agent.vlan_manager.get(
self._net_uuid, self._segmentation_id).vlan
if ip_version == n_const.IP_VERSION_4: if ip_version == n_const.IP_VERSION_4:
expected = [ expected = [
mock.call.delete_dvr_process_ipv4( mock.call.delete_dvr_process_ipv4(
@ -3857,16 +3879,17 @@ class TestOvsDvrNeutronAgent(object):
mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br): mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br):
self.agent.port_bound( self.agent.port_bound(
self._port, self._net_uuid, 'vxlan', self._port, self._net_uuid, 'vxlan',
None, None, self._fixed_ips, None, self._segmentation_id, self._fixed_ips,
n_const.DEVICE_OWNER_DVR_INTERFACE, n_const.DEVICE_OWNER_DVR_INTERFACE,
False) False)
lvid = self.agent.vlan_manager.get(self._net_uuid).vlan lvid = self.agent.vlan_manager.get(
self._net_uuid, self._segmentation_id).vlan
int_br.assert_has_calls( int_br.assert_has_calls(
self._expected_port_bound(self._port, lvid), any_order=True) self._expected_port_bound(self._port, lvid), any_order=True)
expected_on_tun_br = [ expected_on_tun_br = [
mock.call.provision_local_vlan( mock.call.provision_local_vlan(
network_type='vxlan', network_type='vxlan',
segmentation_id=None, segmentation_id=self._segmentation_id,
lvid=lvid, lvid=lvid,
distributed=True), distributed=True),
] + self._expected_install_dvr_process( ] + self._expected_install_dvr_process(
@ -3879,7 +3902,7 @@ class TestOvsDvrNeutronAgent(object):
tun_br.reset_mock() tun_br.reset_mock()
self.agent.port_bound(self._compute_port, self.agent.port_bound(self._compute_port,
self._net_uuid, 'vxlan', self._net_uuid, 'vxlan',
None, None, None, self._segmentation_id,
self._compute_fixed_ips, self._compute_fixed_ips,
device_owner, False) device_owner, False)
int_br.assert_has_calls( int_br.assert_has_calls(
@ -3958,10 +3981,11 @@ class TestOvsDvrNeutronAgent(object):
mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br): mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br):
self.agent.port_bound( self.agent.port_bound(
self._port, self._net_uuid, 'vxlan', self._port, self._net_uuid, 'vxlan',
None, None, self._fixed_ips, None, self._segmentation_id, self._fixed_ips,
n_const.DEVICE_OWNER_ROUTER_SNAT, n_const.DEVICE_OWNER_ROUTER_SNAT,
False) False)
lvid = self.agent.vlan_manager.get(self._net_uuid).vlan lvid = self.agent.vlan_manager.get(
self._net_uuid, self._segmentation_id).vlan
expected_on_int_br = [ expected_on_int_br = [
mock.call.install_dvr_to_src_mac( mock.call.install_dvr_to_src_mac(
network_type='vxlan', network_type='vxlan',
@ -3976,7 +4000,7 @@ class TestOvsDvrNeutronAgent(object):
mock.call.provision_local_vlan( mock.call.provision_local_vlan(
network_type='vxlan', network_type='vxlan',
lvid=lvid, lvid=lvid,
segmentation_id=None, segmentation_id=self._segmentation_id,
distributed=True, distributed=True,
), ),
] ]

View File

@ -455,7 +455,7 @@ class TunnelTest(object):
a = self._build_agent() a = self._build_agent()
a.available_local_vlans = set() a.available_local_vlans = set()
a.vlan_manager.add(NET_UUID, *self.LVM_DATA) a.vlan_manager.add(NET_UUID, *self.LVM_DATA)
a.reclaim_local_vlan(NET_UUID) a.reclaim_local_vlan(NET_UUID, LS_ID)
self.assertIn(self.LVM_DATA[0], a.available_local_vlans) self.assertIn(self.LVM_DATA[0], a.available_local_vlans)
self._verify_mock_calls() self._verify_mock_calls()
@ -475,7 +475,7 @@ class TunnelTest(object):
a.available_local_vlans = set() a.available_local_vlans = set()
a.vlan_manager.add(NET_UUID, *self.LVM_FLAT_DATA) a.vlan_manager.add(NET_UUID, *self.LVM_FLAT_DATA)
a.reclaim_local_vlan(NET_UUID) a.reclaim_local_vlan(NET_UUID, LS_ID)
self.assertIn(self.LVM_FLAT_DATA[0], a.available_local_vlans) self.assertIn(self.LVM_FLAT_DATA[0], a.available_local_vlans)
self._verify_mock_calls() self._verify_mock_calls()
@ -495,7 +495,7 @@ class TunnelTest(object):
a.available_local_vlans = set() a.available_local_vlans = set()
a.vlan_manager.add(NET_UUID, *self.LVM_VLAN_DATA) a.vlan_manager.add(NET_UUID, *self.LVM_VLAN_DATA)
a.reclaim_local_vlan(NET_UUID) a.reclaim_local_vlan(NET_UUID, LS_ID)
self.assertIn(self.LVM_VLAN_DATA[0], a.available_local_vlans) self.assertIn(self.LVM_VLAN_DATA[0], a.available_local_vlans)
self._verify_mock_calls() self._verify_mock_calls()
@ -528,7 +528,7 @@ class TunnelTest(object):
a.vlan_manager.add(NET_UUID, *self.LVM_DATA) a.vlan_manager.add(NET_UUID, *self.LVM_DATA)
a.port_unbound(VIF_ID, NET_UUID) a.port_unbound(VIF_ID, NET_UUID)
reclaim_local_vlan.assert_called_once_with(NET_UUID) reclaim_local_vlan.assert_called_once_with(NET_UUID, LS_ID)
self._verify_mock_calls() self._verify_mock_calls()
def test_port_dead(self): def test_port_dead(self):

View File

@ -72,29 +72,30 @@ class TestLocalVlanManager(base.BaseTestCase):
created_vlans = [] created_vlans = []
for val in range(3): for val in range(3):
self.vlan_manager.add(val, val, val, val, val) self.vlan_manager.add(val, val, val, val, val)
created_vlans.append(self.vlan_manager.get(val)) created_vlans.append({val: self.vlan_manager.get(val, val)})
self.assertCountEqual(created_vlans, list(self.vlan_manager)) self.assertCountEqual(created_vlans, list(self.vlan_manager))
def test_get_net_uuid_existing(self): def test_get_net_and_segmentation_id_existing(self):
port_id = 'port-id' port_id = 'port-id'
vlan_data = (2, 3, 4, 5, {port_id: 'port'}) vlan_data = (2, 3, 4, 5, {port_id: 'port'})
net_id = 1 net_id = 1
self.vlan_manager.add(net_id, *vlan_data) self.vlan_manager.add(net_id, *vlan_data)
obtained_net_id = self.vlan_manager.get_net_uuid(port_id) obtained_net_id = (
self.assertEqual(net_id, obtained_net_id) self.vlan_manager.get_net_and_segmentation_id(port_id))
self.assertEqual((net_id, 5), obtained_net_id)
def test_get_net_uuid_non_existing_raises_exception(self): def test_get_net_and_segmentation_id_non_existing_raises_exception(self):
vlan_data = (1, 2, 3, 4, 5, {'port_id': 'port'}) vlan_data = (1, 2, 3, 4, 5, {'port_id': 'port'})
self.vlan_manager.add(*vlan_data) self.vlan_manager.add(*vlan_data)
with testtools.ExpectedException(vlanmanager.VifIdNotFound): with testtools.ExpectedException(vlanmanager.VifIdNotFound):
self.vlan_manager.get_net_uuid('non-existing-port') self.vlan_manager.get_net_and_segmentation_id('non-existing-port')
def test_add_and_get(self): def test_add_and_get(self):
vlan_data = (2, 3, 4, 5, 6) vlan_data = (2, 3, 4, 5, 6)
expected_vlan_mapping = vlanmanager.LocalVLANMapping(*vlan_data) expected_vlan_mapping = vlanmanager.LocalVLANMapping(*vlan_data)
self.vlan_manager.add(1, *vlan_data) self.vlan_manager.add(1, *vlan_data)
vlan_mapping = self.vlan_manager.get(1) vlan_mapping = self.vlan_manager.get(1, 5)
self.assertEqual(expected_vlan_mapping, vlan_mapping) self.assertEqual(expected_vlan_mapping, vlan_mapping)
def test_add_existing_raises_exception(self): def test_add_existing_raises_exception(self):
@ -105,23 +106,39 @@ class TestLocalVlanManager(base.BaseTestCase):
def test_get_non_existing_raises_keyerror(self): def test_get_non_existing_raises_keyerror(self):
with testtools.ExpectedException(vlanmanager.MappingNotFound): with testtools.ExpectedException(vlanmanager.MappingNotFound):
self.vlan_manager.get(1) self.vlan_manager.get(1, 5)
def test_pop(self): def test_pop(self):
vlan_data = (2, 3, 4, 5, 6) vlan_data = (2, 3, 4, 5, 6)
expected_vlan_mapping = vlanmanager.LocalVLANMapping(*vlan_data) expected_vlan_mapping = vlanmanager.LocalVLANMapping(*vlan_data)
self.vlan_manager.add(1, *vlan_data) self.vlan_manager.add(1, *vlan_data)
vlan_mapping = self.vlan_manager.pop(1) vlan_mapping = self.vlan_manager.pop(1, 5)
self.assertEqual(expected_vlan_mapping, vlan_mapping) self.assertEqual(expected_vlan_mapping, vlan_mapping)
self.assertFalse(self.vlan_manager.mapping) self.assertFalse(self.vlan_manager.mapping)
def test_pop_non_existing_raises_exception(self): def test_pop_non_existing_raises_exception(self):
with testtools.ExpectedException(vlanmanager.MappingNotFound): with testtools.ExpectedException(vlanmanager.MappingNotFound):
self.vlan_manager.pop(1) self.vlan_manager.pop(1, 5)
def test_update_segmentation_id(self): def test_update_segmentation_id(self):
self.vlan_manager.add('net_id', 'vlan_id', 'vlan', 'phys_net', self.vlan_manager.add('net_id', 'vlan_id', 'vlan', 'phys_net',
1001, None) 1001, None)
self.assertEqual(1001, self.vlan_manager.get('net_id').segmentation_id) self.assertEqual(1001, self.vlan_manager.get(
'net_id', 1001).segmentation_id)
self.vlan_manager.update_segmentation_id('net_id', 1002) self.vlan_manager.update_segmentation_id('net_id', 1002)
self.assertEqual(1002, self.vlan_manager.get('net_id').segmentation_id) self.assertEqual(1002, self.vlan_manager.get(
'net_id', 1002).segmentation_id)
def test_update_segmentation_id_not_found(self):
with testtools.ExpectedException(vlanmanager.MappingNotFound):
self.vlan_manager.update_segmentation_id(
'net_id-notfound', 1002)
def test_update_segmentation_id_not_uniq(self):
self.vlan_manager.add('net_id-not-uniq', 'vlan_id', 'vlan', 'phys_net',
1001, None)
self.vlan_manager.add('net_id-not-uniq', 'vlan_id', 'vlan', 'phys_net',
1002, None)
with testtools.ExpectedException(vlanmanager.NotUniqMapping):
self.vlan_manager.update_segmentation_id(
'net_id-not-uniq', 1003)