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()
for network_id, values in fdb_entries.items():
try:
lvm = vlan_manager.get(network_id)
lvm = vlan_manager.get(
network_id, values.get('segment_id'))
except vlanmanager.MappingNotFound:
continue
agent_ports = values.get('ports')
@ -307,10 +308,11 @@ class L2populationRpcCallBackTunnelMixin(L2populationRpcCallBackMixin,
vlan_manager = vlanmanager.LocalVlanManager()
for network_id, agent_ports in fdb_entries.items():
try:
lvm = vlan_manager.get(network_id)
lvms = vlan_manager.get_segments(network_id)
except vlanmanager.MappingNotFound:
continue
for lvm in lvms.values():
for agent_ip, state in agent_ports.items():
if agent_ip == local_ip:
continue

View File

@ -490,15 +490,20 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
return
try:
lvm = self.vlan_manager.get(network['id'])
except vlanmanager.MappingNotFound:
segmentation_id_old, lvm = (
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
segmentation_id_old = lvm.segmentation_id
if segmentation_id_old == network[provider_net.SEGMENTATION_ID]:
if segmentation_id_old is None:
# The segmentation id did not changed.
return
self.vlan_manager.update_segmentation_id(
network['id'], network[provider_net.SEGMENTATION_ID])
lvid = lvm.vlan
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):
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:
return self.vlan_manager.get(net_id).vlan
return self.vlan_manager.get(net_id, segmentation_id).vlan
except vlanmanager.MappingNotFound:
return None
@ -982,22 +987,25 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
tags available.
"""
try:
lvm = self.vlan_manager.get(net_uuid)
lvm = self.vlan_manager.get(net_uuid, segmentation_id)
except vlanmanager.MappingNotFound:
lvid = self._local_vlan_hints.pop(net_uuid, None)
if lvid is None:
if not self.available_local_vlans:
LOG.error("No local VLAN available for net-id=%s",
net_uuid)
LOG.error("No local VLAN available for net-id=%s, "
"seg-id=%s",
net_uuid, segmentation_id)
return
lvid = self.available_local_vlans.pop()
self.vlan_manager.add(
net_uuid, lvid, network_type, physical_network,
segmentation_id)
lvm = self.vlan_manager.get(net_uuid)
lvm = self.vlan_manager.get(net_uuid, segmentation_id)
LOG.info(
"Assigning %(vlan_id)s as local vlan for net-id=%(net_uuid)s",
{'vlan_id': lvm.vlan, 'net_uuid': net_uuid})
"Assigning %(vlan_id)s as local vlan for net-id=%(net_uuid)s, "
"seg-id=%(seg_id)s",
{'vlan_id': lvm.vlan, 'net_uuid': net_uuid,
'seg_id': segmentation_id})
return lvm
@ -1067,20 +1075,23 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
{'network_type': network_type,
'net_uuid': net_uuid})
def reclaim_local_vlan(self, net_uuid):
def reclaim_local_vlan(self, net_uuid, segmentation_id):
'''Reclaim a local VLAN.
:param net_uuid: the network uuid associated with this vlan.
'''
try:
lvm = vlanmanager.LocalVlanManager().pop(net_uuid)
lvm = vlanmanager.LocalVlanManager().pop(
net_uuid, segmentation_id)
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
LOG.info("Reclaiming vlan = %(vlan_id)s from "
"net-id = %(net_uuid)s",
{'vlan_id': lvm.vlan, 'net_uuid': net_uuid})
"net-id = %(net_uuid)s, seg-id = %(seg_id)s",
{'vlan_id': lvm.vlan, 'net_uuid': net_uuid,
'seg_id': segmentation_id})
if lvm.network_type in ovs_const.TUNNEL_NETWORK_TYPES:
if self.enable_tunneling:
@ -1158,10 +1169,15 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
restart or recreated physical bridges
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,
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
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}
for port_detail in need_binding_ports:
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:
# network for port was deleted. skip this port since it
# will need to be handled as a DEAD port in the next scan
@ -1322,14 +1339,22 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
def _get_port_lvm_and_vif(self, vif_id, net_uuid=None):
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:
LOG.info('net_uuid %s not managed by VLAN manager',
net_uuid)
if net_uuid:
# TODO(sahid); This needs to be fixed. It supposes a segment
# 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
lvm = self.vlan_manager.get(net_uuid)
if vif_id in lvm.vif_ports:
vif_port = lvm.vif_ports[vif_id]
return lvm, vif_port, net_uuid
@ -1352,9 +1377,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
if vif_port and vif_id in lvm.vif_ports:
self.dvr_agent.unbind_port_from_dvr(vif_port, lvm)
lvm.vif_ports.pop(vif_id, None)
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):
cur_tag = self.int_br.db_get_val("Port", port.port_name, "tag",
@ -1811,7 +1835,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
"""
port_tags = self.int_br.get_port_tag_dict()
changed_ports = set()
for lvm in self.vlan_manager:
for vlan_mappings in self.vlan_manager:
for lvm in vlan_mappings.values():
for port in lvm.vif_ports.values():
if (
port.port_name in port_tags and
@ -1820,7 +1845,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
LOG.info(
"Port '%(port_name)s' has lost "
"its vlan tag '%(vlan_tag)d'! "
"Current vlan tag on this port is '%(new_vlan_tag)s'.",
"Current vlan tag on this port is "
"'%(new_vlan_tag)s'.",
{'port_name': port.port_name,
'vlan_tag': lvm.vlan,
'new_vlan_tag': port_tags[port.port_name]}
@ -1906,7 +1932,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
ofports = self.tun_br_ofports[tunnel_type].values()
if ofports and not self.l2_pop:
# Update flooding flows to include the new tunnel
for vlan_mapping in self.vlan_manager:
for vlan_mappings in self.vlan_manager:
for vlan_mapping in vlan_mappings.values():
if vlan_mapping.network_type == tunnel_type:
br.install_flood_to_tun(vlan_mapping.vlan,
vlan_mapping.segmentation_id,
@ -1926,11 +1953,12 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
def cleanup_tunnel_port(self, br, tun_ofport, tunnel_type):
# Check if this tunnel port is still used
for lvm in self.vlan_manager:
for vlan_mappings in self.vlan_manager:
for lvm in vlan_mappings.values():
if tun_ofport in lvm.tun_ofports:
break
# still used
return
# If not, remove it
else:
items = list(self.tun_br_ofports[tunnel_type].items())
for remote_ip, ofport in items:
if ofport == tun_ofport:
@ -1938,7 +1966,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
tunnel_type, self.local_ip, remote_ip)
br.delete_port(port_name)
br.cleanup_tunnel_port(ofport)
self.tun_br_ofports[tunnel_type].pop(remote_ip, None)
self.tun_br_ofports[tunnel_type].pop(
remote_ip, None)
def treat_devices_added_or_updated(self, devices, provisioning_needed,
re_added):
@ -1984,7 +2013,7 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
if 'port_id' in details:
details['vif_port'] = port
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",
{'device': device, 'details': details})
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(
n_const.DEVICE_OWNER_COMPUTE_PREFIX):
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(
port['vif_port'].ofport, lvm.vlan)
except Exception as err:
@ -2250,7 +2280,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
port['port_id'], err)
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']
# 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
# under the License.
from collections import defaultdict
from neutron_lib import exceptions
from neutron._i18n import _
@ -24,11 +26,17 @@ class VifIdNotFound(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):
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):
@ -71,7 +79,7 @@ class LocalVlanManager(object):
def __init__(self):
if not hasattr(self, 'mapping'):
self.mapping = {}
self.mapping = defaultdict(dict)
def __contains__(self, key):
return key in self.mapping
@ -86,31 +94,55 @@ class LocalVlanManager(object):
def add(self, net_id, vlan, network_type, physical_network,
segmentation_id, vif_ports=None):
if net_id in self.mapping:
raise MappingAlreadyExists(net_id=net_id)
self.mapping[net_id] = LocalVLANMapping(
try:
if self.get(net_id, segmentation_id):
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)
def get_net_uuid(self, vif_id):
for network_id, vlan_mapping in self.mapping.items():
def get_net_and_segmentation_id(self, vif_id, net_uuid=None):
# TODO(sahid): We should improve algorithm if net_uuid is passed.
for network_id, vlan_mappings in self.mapping.items():
for segmentation_id, vlan_mapping in vlan_mappings.items():
if vif_id in vlan_mapping.vif_ports:
return network_id
return network_id, segmentation_id
raise VifIdNotFound(vif_id=vif_id)
def get(self, net_id):
try:
return self.mapping[net_id]
except KeyError:
raise MappingNotFound(net_id=net_id)
def get(self, net_id, segmentation_id):
if net_id in self.mapping and segmentation_id in self.mapping[net_id]:
return self.mapping[net_id][segmentation_id]
raise MappingNotFound(net_id=net_id, seg_id=segmentation_id)
def pop(self, net_id):
try:
return self.mapping.pop(net_id)
except KeyError:
raise MappingNotFound(net_id=net_id)
def get_segments(self, net_id):
if net_id not in self.mapping:
raise MappingNotFound(net_id=net_id, seg_id="<all>")
return self.mapping[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):
try:
self.mapping[net_id].segmentation_id = segmentation_id
except KeyError:
raise MappingNotFound(net_id=net_id)
"""Returns tuple with segmentation id, lvm in success or None, None"""
if len(self.get_segments(net_id)) != 1:
# Update of segmentation id can work only if network has one
# 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].segid, {self.lvms[i].vif: self.lvms[i].port})
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.lvms[0].net: {

View File

@ -33,7 +33,7 @@ class TestL2populationRpcCallBackTunnelMixin(
def test_get_agent_ports_non_existence_key_in_lvm(self):
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(
self.fdb_entries1):
results[lvm] = agent_ports

View File

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

View File

@ -455,7 +455,7 @@ class TunnelTest(object):
a = self._build_agent()
a.available_local_vlans = set()
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._verify_mock_calls()
@ -475,7 +475,7 @@ class TunnelTest(object):
a.available_local_vlans = set()
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._verify_mock_calls()
@ -495,7 +495,7 @@ class TunnelTest(object):
a.available_local_vlans = set()
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._verify_mock_calls()
@ -528,7 +528,7 @@ class TunnelTest(object):
a.vlan_manager.add(NET_UUID, *self.LVM_DATA)
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()
def test_port_dead(self):

View File

@ -72,29 +72,30 @@ class TestLocalVlanManager(base.BaseTestCase):
created_vlans = []
for val in range(3):
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))
def test_get_net_uuid_existing(self):
def test_get_net_and_segmentation_id_existing(self):
port_id = 'port-id'
vlan_data = (2, 3, 4, 5, {port_id: 'port'})
net_id = 1
self.vlan_manager.add(net_id, *vlan_data)
obtained_net_id = self.vlan_manager.get_net_uuid(port_id)
self.assertEqual(net_id, obtained_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'})
self.vlan_manager.add(*vlan_data)
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):
vlan_data = (2, 3, 4, 5, 6)
expected_vlan_mapping = vlanmanager.LocalVLANMapping(*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)
def test_add_existing_raises_exception(self):
@ -105,23 +106,39 @@ class TestLocalVlanManager(base.BaseTestCase):
def test_get_non_existing_raises_keyerror(self):
with testtools.ExpectedException(vlanmanager.MappingNotFound):
self.vlan_manager.get(1)
self.vlan_manager.get(1, 5)
def test_pop(self):
vlan_data = (2, 3, 4, 5, 6)
expected_vlan_mapping = vlanmanager.LocalVLANMapping(*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.assertFalse(self.vlan_manager.mapping)
def test_pop_non_existing_raises_exception(self):
with testtools.ExpectedException(vlanmanager.MappingNotFound):
self.vlan_manager.pop(1)
self.vlan_manager.pop(1, 5)
def test_update_segmentation_id(self):
self.vlan_manager.add('net_id', 'vlan_id', 'vlan', 'phys_net',
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.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)