[OVN] Check new added segments in OVN mech driver
Check new segments added to OVN mechanism driver. This mechanism driver does not inherit from ``SimpleAgentMechanismDriverBase`` because OVN has no agents (NOTE 1). However OVN mechanism driver requires an OVN controller service in each deployed chassis. This is how OVN driver knows the hosts using this backend. The segments, attached to an external network (connected to a physical network), can be mapped to a host if ther is a chassis (OVN controller agent) in this host. NOTE 1: OVN provides agent API compatibility, presenting the controller and the metadata services as agents. But OVN mechanism driver has no control or provides any information (via RPC) to those services. Closes-Bug: #1949967 Change-Id: I570b2251da8a4a25d155ba838346b24afafd727f
This commit is contained in:
@@ -69,6 +69,9 @@ OVN_AGENT_METADATA_ID_KEY = 'neutron:ovn-metadata-id'
|
||||
OVN_CONTROLLER_AGENT = 'OVN Controller agent'
|
||||
OVN_CONTROLLER_GW_AGENT = 'OVN Controller Gateway agent'
|
||||
OVN_METADATA_AGENT = 'OVN Metadata agent'
|
||||
OVN_CONTROLLER_TYPES = (OVN_CONTROLLER_AGENT,
|
||||
OVN_CONTROLLER_GW_AGENT,
|
||||
)
|
||||
|
||||
# OVN ACLs have priorities. The highest priority ACL that matches is the one
|
||||
# that takes effect. Our choice of priority numbers is arbitrary, but it
|
||||
|
||||
@@ -364,6 +364,8 @@ class SimpleAgentMechanismDriverBase(AgentMechanismDriverBase,
|
||||
determine whether or not the specified network segment can be
|
||||
bound for the agent.
|
||||
"""
|
||||
if agent['agent_type'] != self.agent_type:
|
||||
return False
|
||||
|
||||
mappings = self.get_mappings(agent)
|
||||
allowed_network_types = self.get_allowed_network_types(agent)
|
||||
|
||||
@@ -177,6 +177,9 @@ class SriovNicSwitchMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
|
||||
:param agent: agents_db entry describing agent to bind or None
|
||||
:returns: True if segment can be bound for agent
|
||||
"""
|
||||
if agent and agent['agent_type'] != self.agent_type:
|
||||
return False
|
||||
|
||||
network_type = segment[api.NETWORK_TYPE]
|
||||
if network_type in self.get_allowed_network_types(agent):
|
||||
if agent:
|
||||
|
||||
@@ -33,6 +33,7 @@ from neutron_lib import exceptions as n_exc
|
||||
from neutron_lib.exceptions import availability_zone as az_exc
|
||||
from neutron_lib.plugins import directory
|
||||
from neutron_lib.plugins.ml2 import api
|
||||
from neutron_lib.utils import helpers
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_db import exception as os_db_exc
|
||||
@@ -1138,6 +1139,20 @@ class OVNMechanismDriver(api.MechanismDriver):
|
||||
if phynet in phynets}
|
||||
segment_service_db.map_segment_to_hosts(context, segment.id, hosts)
|
||||
|
||||
def check_segment_for_agent(self, segment, agent):
|
||||
"""Check if the OVN controller agent br mappings has segment physnet
|
||||
|
||||
Only segments on physical networks (flat or vlan) can be associated
|
||||
to a host.
|
||||
"""
|
||||
if agent['agent_type'] not in ovn_const.OVN_CONTROLLER_TYPES:
|
||||
return False
|
||||
|
||||
br_map = agent.get('configurations', {}).get('bridge-mappings', '')
|
||||
mapping_dict = helpers.parse_mappings(br_map.split(','),
|
||||
unique_values=False)
|
||||
return segment['physical_network'] in mapping_dict
|
||||
|
||||
def patch_plugin_merge(self, method_name, new_fn, op=operator.add):
|
||||
old_method = getattr(self._plugin, method_name)
|
||||
|
||||
|
||||
@@ -2350,8 +2350,9 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
|
||||
def check_segment_for_agent(self, segment, agent):
|
||||
for mech_driver in self.mechanism_manager.ordered_mech_drivers:
|
||||
driver_agent_type = getattr(mech_driver.obj, 'agent_type', None)
|
||||
if driver_agent_type and driver_agent_type == agent['agent_type']:
|
||||
# TODO(ralonsoh): add "check_segment_for_agent" method to ABC
|
||||
# "MechanismDriver", returning False by default.
|
||||
if hasattr(mech_driver.obj, 'check_segment_for_agent'):
|
||||
if mech_driver.obj.check_segment_for_agent(segment, agent):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -246,17 +246,19 @@ class AgentMechanismGenericTestCase(AgentMechanismBaseTestCase):
|
||||
api.NETWORK_ID: 'fake_network_id'}]
|
||||
|
||||
def test_unknown_type(self):
|
||||
context = FakePortContext(self.AGENT_TYPE,
|
||||
self.AGENTS,
|
||||
self.UNKNOWN_TYPE_SEGMENTS,
|
||||
vnic_type=self.VNIC_TYPE)
|
||||
self.context = FakePortContext(self.AGENT_TYPE, self.AGENTS,
|
||||
self.UNKNOWN_TYPE_SEGMENTS,
|
||||
vnic_type=self.VNIC_TYPE)
|
||||
context = self.context
|
||||
self.driver.bind_port(context)
|
||||
self._check_unbound(context)
|
||||
|
||||
def test_driver_not_responsible_for_ports_allocation(self):
|
||||
agents = [
|
||||
{'configurations': {'rp_bandwidths': {'eth0': {}}},
|
||||
'host': 'host'},
|
||||
'host': 'host',
|
||||
'agent_type': self.AGENT_TYPE,
|
||||
},
|
||||
]
|
||||
profile = {}
|
||||
segments = []
|
||||
|
||||
@@ -38,16 +38,24 @@ class LinuxbridgeMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
|
||||
|
||||
AGENTS = [{'alive': True,
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'host': 'host'}]
|
||||
'host': 'host',
|
||||
'agent_type': AGENT_TYPE,
|
||||
}]
|
||||
AGENTS_DEAD = [{'alive': False,
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'host': 'dead_host'}]
|
||||
'host': 'dead_host',
|
||||
'agent_type': AGENT_TYPE,
|
||||
}]
|
||||
AGENTS_BAD = [{'alive': False,
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'host': 'bad_host_1'},
|
||||
'host': 'bad_host_1',
|
||||
'agent_type': AGENT_TYPE,
|
||||
},
|
||||
{'alive': True,
|
||||
'configurations': BAD_CONFIGS,
|
||||
'host': 'bad_host_2'}]
|
||||
'host': 'bad_host_2',
|
||||
'agent_type': AGENT_TYPE,
|
||||
}]
|
||||
|
||||
def setUp(self):
|
||||
super(LinuxbridgeMechanismBaseTestCase, self).setUp()
|
||||
|
||||
@@ -34,18 +34,26 @@ class MacvtapMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
|
||||
|
||||
AGENT = {'alive': True,
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'host': 'host'}
|
||||
'host': 'host',
|
||||
'agent_type': AGENT_TYPE,
|
||||
}
|
||||
AGENTS = [AGENT]
|
||||
|
||||
AGENTS_DEAD = [{'alive': False,
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'host': 'dead_host'}]
|
||||
'host': 'dead_host',
|
||||
'agent_type': AGENT_TYPE,
|
||||
}]
|
||||
AGENTS_BAD = [{'alive': False,
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'host': 'bad_host_1'},
|
||||
'host': 'bad_host_1',
|
||||
'agent_type': AGENT_TYPE,
|
||||
},
|
||||
{'alive': True,
|
||||
'configurations': BAD_CONFIGS,
|
||||
'host': 'bad_host_2'}]
|
||||
'host': 'bad_host_2',
|
||||
'agent_type': AGENT_TYPE,
|
||||
}]
|
||||
|
||||
def setUp(self):
|
||||
super(MacvtapMechanismBaseTestCase, self).setUp()
|
||||
|
||||
@@ -58,13 +58,21 @@ class SriovNicSwitchMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
|
||||
BAD_CONFIGS = {'device_mappings': BAD_MAPPINGS}
|
||||
|
||||
AGENTS = [{'alive': True,
|
||||
'configurations': GOOD_CONFIGS}]
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'agent_type': AGENT_TYPE,
|
||||
}]
|
||||
AGENTS_DEAD = [{'alive': False,
|
||||
'configurations': GOOD_CONFIGS}]
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'agent_type': AGENT_TYPE,
|
||||
}]
|
||||
AGENTS_BAD = [{'alive': False,
|
||||
'configurations': GOOD_CONFIGS},
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'agent_type': AGENT_TYPE,
|
||||
},
|
||||
{'alive': True,
|
||||
'configurations': BAD_CONFIGS}]
|
||||
'configurations': BAD_CONFIGS,
|
||||
'agent_type': AGENT_TYPE,
|
||||
}]
|
||||
|
||||
def setUp(self):
|
||||
super(SriovNicSwitchMechanismBaseTestCase, self).setUp()
|
||||
@@ -76,17 +84,23 @@ class SriovSwitchMechGenericTestCase(SriovNicSwitchMechanismBaseTestCase,
|
||||
base.AgentMechanismGenericTestCase):
|
||||
def test_check_segment(self):
|
||||
"""Validate the check_segment call."""
|
||||
segment = {'api.NETWORK_TYPE': ""}
|
||||
segment[api.NETWORK_TYPE] = constants.TYPE_VLAN
|
||||
self.assertTrue(self.driver.check_segment_for_agent(segment))
|
||||
agent = {'agent_type': self.AGENT_TYPE,
|
||||
'configurations': {'device_mappings': ['physnet1']}}
|
||||
segment = {api.NETWORK_TYPE: constants.TYPE_VLAN,
|
||||
api.PHYSICAL_NETWORK: 'physnet1'}
|
||||
self.assertTrue(self.driver.check_segment_for_agent(segment, agent))
|
||||
# Validate a network type not currently supported
|
||||
segment[api.NETWORK_TYPE] = constants.TYPE_GRE
|
||||
self.assertFalse(self.driver.check_segment_for_agent(segment))
|
||||
self.assertFalse(self.driver.check_segment_for_agent(segment, agent))
|
||||
|
||||
def test_check_segment_allows_supported_network_types(self):
|
||||
for network_type in self.driver.get_allowed_network_types(agent=None):
|
||||
segment = {api.NETWORK_TYPE: network_type}
|
||||
self.assertTrue(self.driver.check_segment_for_agent(segment))
|
||||
agent = {'agent_type': self.AGENT_TYPE,
|
||||
'configurations': {'device_mappings': ['physnet1']}}
|
||||
segment = {api.NETWORK_TYPE: network_type,
|
||||
api.PHYSICAL_NETWORK: 'physnet1'}
|
||||
self.assertTrue(self.driver.check_segment_for_agent(segment,
|
||||
agent))
|
||||
|
||||
def test_driver_responsible_for_ports_allocation(self):
|
||||
agents = [
|
||||
|
||||
@@ -55,16 +55,24 @@ class OpenvswitchMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
|
||||
|
||||
AGENTS = [{'alive': True,
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'host': 'host'}]
|
||||
'host': 'host',
|
||||
'agent_type': AGENT_TYPE,
|
||||
}]
|
||||
AGENTS_DEAD = [{'alive': False,
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'host': 'dead_host'}]
|
||||
'host': 'dead_host',
|
||||
'agent_type': AGENT_TYPE,
|
||||
}]
|
||||
AGENTS_BAD = [{'alive': False,
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'host': 'bad_host_1'},
|
||||
'host': 'bad_host_1',
|
||||
'agent_type': AGENT_TYPE,
|
||||
},
|
||||
{'alive': True,
|
||||
'configurations': BAD_CONFIGS,
|
||||
'host': 'bad_host_2'}]
|
||||
'host': 'bad_host_2',
|
||||
'agent_type': AGENT_TYPE,
|
||||
}]
|
||||
|
||||
def setUp(self):
|
||||
super(OpenvswitchMechanismBaseTestCase, self).setUp()
|
||||
@@ -128,7 +136,9 @@ class OpenvswitchMechanismSGDisabledBaseTestCase(
|
||||
'tunnel_types': GOOD_TUNNEL_TYPES}
|
||||
AGENTS = [{'alive': True,
|
||||
'configurations': GOOD_CONFIGS,
|
||||
'host': 'host'}]
|
||||
'host': 'host',
|
||||
'agent_type': constants.AGENT_TYPE_OVS,
|
||||
}]
|
||||
|
||||
def setUp(self):
|
||||
cfg.CONF.set_override('enable_security_group',
|
||||
@@ -151,7 +161,9 @@ class OpenvswitchMechanismHybridPlugTestCase(OpenvswitchMechanismBaseTestCase):
|
||||
self.driver.vif_details[hybrid] = False
|
||||
agents = [{'alive': True,
|
||||
'configurations': {hybrid: True},
|
||||
'host': 'host'}]
|
||||
'host': 'host',
|
||||
'agent_type': self.AGENT_TYPE,
|
||||
}]
|
||||
context = self._make_port_ctx(agents)
|
||||
self.driver.bind_port(context)
|
||||
self.assertTrue(context._bound_vif_details[hybrid])
|
||||
@@ -163,7 +175,9 @@ class OpenvswitchMechanismHybridPlugTestCase(OpenvswitchMechanismBaseTestCase):
|
||||
self.driver.vif_details[hybrid] = True
|
||||
agents = [{'alive': True,
|
||||
'configurations': {hybrid: False},
|
||||
'host': 'host'}]
|
||||
'host': 'host',
|
||||
'agent_type': self.AGENT_TYPE,
|
||||
}]
|
||||
context = self._make_port_ctx(agents)
|
||||
self.driver.bind_port(context)
|
||||
self.assertFalse(context._bound_vif_details[hybrid])
|
||||
|
||||
@@ -2607,6 +2607,25 @@ class TestOVNMechanismDriverSegment(MechDriverSetupBase,
|
||||
3,
|
||||
ovn_nb_api.delete_lswitch_port.call_count)
|
||||
|
||||
def test_check_segment_for_agent(self):
|
||||
segment = {'physical_network': 'physnet1'}
|
||||
agent = {'agent_type': ovn_const.OVN_METADATA_AGENT}
|
||||
self.assertFalse(
|
||||
self.mech_driver.check_segment_for_agent(segment, agent))
|
||||
|
||||
agent = {'agent_type': ovn_const.OVN_CONTROLLER_AGENT,
|
||||
'configurations': {}}
|
||||
self.assertFalse(
|
||||
self.mech_driver.check_segment_for_agent(segment, agent))
|
||||
|
||||
agent['configurations'] = {'bridge-mappings': 'physnet2:br-ex2'}
|
||||
self.assertFalse(
|
||||
self.mech_driver.check_segment_for_agent(segment, agent))
|
||||
|
||||
agent['configurations'] = {'bridge-mappings': 'physnet1:br-ex1'}
|
||||
self.assertTrue(
|
||||
self.mech_driver.check_segment_for_agent(segment, agent))
|
||||
|
||||
|
||||
@mock.patch.object(n_net, 'get_random_mac', lambda *_: '01:02:03:04:05:06')
|
||||
class TestOVNMechanismDriverDHCPOptions(OVNMechanismDriverTestCase):
|
||||
|
||||
Reference in New Issue
Block a user