[OVN] Add the bridge name and datapath type to the port VIF details
Same as in ML2/OVS, the ML2/OVN mechanism driver adds to the port VIF details dictionary the OVS bridge the port is connected to and the integration bridge datapath type. Closes-Bug: #2045889 Change-Id: Ifda46c42b9506449a58fbaf312cc71c72d9cf2df
This commit is contained in:
parent
97b84180b2
commit
baaf240ce3
@ -370,6 +370,18 @@ class MetadataAgent(object):
|
||||
LOG.debug("Loaded chassis name %s (UUID: %s) and ovn bridge %s.",
|
||||
self.chassis, self.chassis_id, self.ovn_bridge)
|
||||
|
||||
def _update_chassis_private_config(self):
|
||||
"""Update the Chassis_Private register information
|
||||
|
||||
This method should be called once the Metadata Agent has been
|
||||
registered (method ``register_metadata_agent`` has been called) and
|
||||
the corresponding Chassis_Private register has been created/updated.
|
||||
"""
|
||||
external_ids = {ovn_const.OVN_AGENT_OVN_BRIDGE: self.ovn_bridge}
|
||||
self.sb_idl.db_set(
|
||||
'Chassis_Private', self.chassis,
|
||||
('external_ids', external_ids)).execute(check_error=True)
|
||||
|
||||
@_sync_lock
|
||||
def resync(self):
|
||||
"""Resync the agent.
|
||||
@ -377,6 +389,7 @@ class MetadataAgent(object):
|
||||
Reload the configuration and sync the agent again.
|
||||
"""
|
||||
self._load_config()
|
||||
self._update_chassis_private_config()
|
||||
self.sync()
|
||||
|
||||
def start(self):
|
||||
@ -409,6 +422,7 @@ class MetadataAgent(object):
|
||||
|
||||
# Register the agent with its corresponding Chassis
|
||||
self.register_metadata_agent()
|
||||
self._update_chassis_private_config()
|
||||
|
||||
self._proxy.wait()
|
||||
|
||||
|
@ -92,3 +92,7 @@ METADATA_V6_CIDR = constants.METADATA_V6_IP + '/128'
|
||||
|
||||
# TODO(haleyb): move this constant to neutron_lib.constants
|
||||
IPV4_MIN_MTU = 68
|
||||
|
||||
|
||||
# TODO(ralonsoh): move this constant to neutron_lib.plugins.ml2.ovs_constants
|
||||
DEFAULT_BR_INT = 'br-int'
|
||||
|
@ -72,6 +72,8 @@ OVN_NAME_PREFIX = 'neutron-'
|
||||
OVN_HA_CH_GROUP_EXTPORT_PREFIX = 'neutron-extport-'
|
||||
OVN_METADATA_PREFIX = 'ovnmeta-'
|
||||
|
||||
OVN_DATAPATH_TYPE = 'datapath-type'
|
||||
|
||||
# TODO(froyo): Move this to neutron-lib as soon as possible, and when a new
|
||||
# release is created and pointed to in the requirements remove this code
|
||||
OVN_LB_HM_PORT_DISTRIBUTED = 'ovn-lb-hm:distributed'
|
||||
@ -84,6 +86,7 @@ OVN_AGENT_METADATA_ID_KEY = 'neutron:ovn-metadata-id'
|
||||
OVN_AGENT_NEUTRON_SB_CFG_KEY = 'neutron:ovn-neutron-agent-sb-cfg'
|
||||
OVN_AGENT_NEUTRON_DESC_KEY = 'neutron:description-neutron-agent'
|
||||
OVN_AGENT_NEUTRON_ID_KEY = 'neutron:ovn-neutron-agent-id'
|
||||
OVN_AGENT_OVN_BRIDGE = 'neutron:ovn-bridge'
|
||||
OVN_CONTROLLER_AGENT = 'OVN Controller agent'
|
||||
OVN_CONTROLLER_GW_AGENT = 'OVN Controller Gateway agent'
|
||||
OVN_METADATA_AGENT = 'OVN Metadata agent'
|
||||
|
@ -40,6 +40,7 @@ from ovsdbapp import constants as ovsdbapp_const
|
||||
import tenacity
|
||||
|
||||
from neutron._i18n import _
|
||||
from neutron.common import _constants as n_const
|
||||
from neutron.common.ovn import constants
|
||||
from neutron.common.ovn import exceptions as ovn_exc
|
||||
from neutron.common import utils as common_utils
|
||||
@ -707,6 +708,31 @@ def get_ovn_cms_options(chassis):
|
||||
constants.OVN_CMS_OPTIONS, '').split(',')]
|
||||
|
||||
|
||||
def get_ovn_bridge_from_chassis_private(chassis_private):
|
||||
"""Return the OVN bridge used by the local OVN controller
|
||||
|
||||
This information is stored in the Chassis_Private register by the OVN
|
||||
Metadata agent. The default value returned, if not present, is "br-int".
|
||||
NOTE: the default value is not reading the local ``OVS.integration_bridge``
|
||||
configuration knob, that could be different.
|
||||
"""
|
||||
return (chassis_private.external_ids.get(constants.OVN_AGENT_OVN_BRIDGE) or
|
||||
n_const.DEFAULT_BR_INT)
|
||||
|
||||
|
||||
def get_datapath_type(hostname, sb_idl):
|
||||
"""Return the local OVS integration bridge datapath type
|
||||
|
||||
If the datapath type is not stored in the ``Chassis`` register or
|
||||
the register is still not created, the default value returned is "".
|
||||
"""
|
||||
chassis = sb_idl.db_find(
|
||||
'Chassis', ('hostname', '=', hostname)).execute(check_error=True)
|
||||
return (
|
||||
chassis[0].get('other_config', {}).get(constants.OVN_DATAPATH_TYPE, '')
|
||||
if chassis else '')
|
||||
|
||||
|
||||
def is_gateway_chassis(chassis):
|
||||
"""Check if the given chassis is a gateway chassis"""
|
||||
return constants.CMS_OPT_CHASSIS_AS_GW in get_ovn_cms_options(chassis)
|
||||
|
@ -11,6 +11,7 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import copy
|
||||
|
||||
from neutron_lib.api.definitions import portbindings as pb_api
|
||||
from neutron_lib import constants
|
||||
@ -21,6 +22,7 @@ from oslo_db import exception as db_exc
|
||||
from oslo_log import log as logging
|
||||
from sqlalchemy.orm import exc as sqla_exc
|
||||
|
||||
from neutron.common import _constants as n_const
|
||||
from neutron.db.models.plugins.ml2 import geneveallocation
|
||||
from neutron.db.models.plugins.ml2 import vxlanallocation
|
||||
from neutron.objects import network as network_obj
|
||||
@ -30,10 +32,6 @@ from neutron.objects import trunk as trunk_obj
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
VIF_DETAILS_TO_REMOVE = (
|
||||
pb_api.VIF_DETAILS_BRIDGE_NAME,
|
||||
)
|
||||
|
||||
|
||||
def migrate_neutron_database_to_ovn():
|
||||
"""Change DB content from OVS to OVN mech driver.
|
||||
@ -75,18 +73,22 @@ def migrate_neutron_database_to_ovn():
|
||||
with db_api.CONTEXT_WRITER.using(ctx):
|
||||
pb = port_obj.PortBinding.get_object(ctx, port_id=port_id,
|
||||
host=host)
|
||||
if not pb or not pb.vif_details:
|
||||
if not pb:
|
||||
continue
|
||||
|
||||
vif_details = pb.vif_details.copy()
|
||||
for detail in VIF_DETAILS_TO_REMOVE:
|
||||
try:
|
||||
del vif_details[detail]
|
||||
except KeyError:
|
||||
pass
|
||||
if vif_details == pb.vif_details:
|
||||
# Update the OVS bridge name in the VIF details: now all
|
||||
# port are directly connected to the integration bridge.
|
||||
# Because the name of each host integration bridge is not
|
||||
# know by the Neutron API at this point, the default value
|
||||
# "br-int" will be used.
|
||||
# The OVS datapath type is unchanged.
|
||||
vif_details = copy.deepcopy(pb.vif_details) or {}
|
||||
if (vif_details.get(pb_api.VIF_DETAILS_BRIDGE_NAME) ==
|
||||
n_const.DEFAULT_BR_INT):
|
||||
continue
|
||||
|
||||
vif_details[pb_api.VIF_DETAILS_BRIDGE_NAME] = (
|
||||
n_const.DEFAULT_BR_INT)
|
||||
pb.vif_details = vif_details
|
||||
pb.update()
|
||||
except (exceptions.ObjectNotFound,
|
||||
|
@ -187,7 +187,7 @@ class OVNMechanismDriver(api.MechanismDriver):
|
||||
vif_types = set()
|
||||
for ch in self.sb_ovn.chassis_list().execute(check_error=True):
|
||||
other_config = ovn_utils.get_ovn_chassis_other_config(ch)
|
||||
dp_type = other_config.get('datapath-type', '')
|
||||
dp_type = other_config.get(ovn_const.OVN_DATAPATH_TYPE, '')
|
||||
if dp_type == ovn_const.CHASSIS_DATAPATH_NETDEV:
|
||||
vif_types.add(portbindings.VIF_TYPE_VHOST_USER)
|
||||
else:
|
||||
@ -990,7 +990,7 @@ class OVNMechanismDriver(api.MechanismDriver):
|
||||
return
|
||||
chassis = agent.chassis
|
||||
other_config = ovn_utils.get_ovn_chassis_other_config(chassis)
|
||||
datapath_type = other_config.get('datapath-type', '')
|
||||
datapath_type = other_config.get(ovn_const.OVN_DATAPATH_TYPE, '')
|
||||
iface_types = other_config.get('iface-types', '')
|
||||
iface_types = iface_types.split(',') if iface_types else []
|
||||
chassis_physnets = self.sb_ovn._get_chassis_physnets(chassis)
|
||||
@ -1037,7 +1037,7 @@ class OVNMechanismDriver(api.MechanismDriver):
|
||||
vif_type = portbindings.VIF_TYPE_VHOST_USER
|
||||
port[portbindings.VIF_DETAILS].update({
|
||||
portbindings.VHOST_USER_SOCKET: vhost_user_socket})
|
||||
vif_details = dict(self.vif_details[vif_type])
|
||||
vif_details = copy.deepcopy(self.vif_details[vif_type])
|
||||
vif_details[portbindings.VHOST_USER_SOCKET] = (
|
||||
vhost_user_socket)
|
||||
elif (vnic_type == portbindings.VNIC_VIRTIO_FORWARDER):
|
||||
@ -1046,15 +1046,22 @@ class OVNMechanismDriver(api.MechanismDriver):
|
||||
vif_type = portbindings.VIF_TYPE_AGILIO_OVS
|
||||
port[portbindings.VIF_DETAILS].update({
|
||||
portbindings.VHOST_USER_SOCKET: vhost_user_socket})
|
||||
vif_details = dict(self.vif_details[vif_type])
|
||||
vif_details = copy.deepcopy(self.vif_details[vif_type])
|
||||
vif_details[portbindings.VHOST_USER_SOCKET] = (
|
||||
vhost_user_socket)
|
||||
vif_details[portbindings.VHOST_USER_MODE] = (
|
||||
portbindings.VHOST_USER_MODE_CLIENT)
|
||||
else:
|
||||
vif_type = portbindings.VIF_TYPE_OVS
|
||||
vif_details = self.vif_details[vif_type]
|
||||
vif_details = copy.deepcopy(self.vif_details[vif_type])
|
||||
|
||||
ovn_bridge = ovn_utils.get_ovn_bridge_from_chassis_private(
|
||||
agent.chassis_private)
|
||||
dp_type = ovn_utils.get_datapath_type(bind_host, self.sb_ovn)
|
||||
vif_details.update({
|
||||
portbindings.VIF_DETAILS_BRIDGE_NAME: ovn_bridge,
|
||||
portbindings.OVS_DATAPATH_TYPE: dp_type,
|
||||
})
|
||||
context.set_binding(segment_to_bind[api.ID], vif_type,
|
||||
vif_details)
|
||||
break
|
||||
|
@ -114,6 +114,11 @@ class TestMetadataAgent(base.TestOVNFunctionalBase):
|
||||
with mock.patch.object(metadata_server.UnixDomainMetadataProxy,
|
||||
'wait'):
|
||||
agt.start()
|
||||
external_ids = agt.sb_idl.db_get(
|
||||
'Chassis_Private', agt.chassis, 'external_ids').execute(
|
||||
check_error=True)
|
||||
self.assertEqual(external_ids[ovn_const.OVN_AGENT_OVN_BRIDGE],
|
||||
self.OVN_BRIDGE)
|
||||
|
||||
# Metadata agent will open connections to OVS and SB databases.
|
||||
# Close connections to them when the test ends,
|
||||
|
@ -43,6 +43,8 @@ OVS_VIF_DETAILS = {
|
||||
portbindings.CAP_PORT_FILTER: True,
|
||||
portbindings.VIF_DETAILS_CONNECTIVITY: portbindings.CONNECTIVITY_L2,
|
||||
portbindings.VIF_DETAILS_BOUND_DRIVERS: {'0': 'ovn'},
|
||||
portbindings.VIF_DETAILS_BRIDGE_NAME: 'br-int',
|
||||
portbindings.OVS_DATAPATH_TYPE: 'system',
|
||||
}
|
||||
VHOSTUSER_VIF_DETAILS = {
|
||||
portbindings.CAP_PORT_FILTER: False,
|
||||
@ -50,34 +52,39 @@ VHOSTUSER_VIF_DETAILS = {
|
||||
'vhostuser_ovs_plug': True,
|
||||
portbindings.VIF_DETAILS_CONNECTIVITY: portbindings.CONNECTIVITY_L2,
|
||||
portbindings.VIF_DETAILS_BOUND_DRIVERS: {'0': 'ovn'},
|
||||
portbindings.VIF_DETAILS_BRIDGE_NAME: 'br-int',
|
||||
portbindings.OVS_DATAPATH_TYPE: 'netdev',
|
||||
}
|
||||
|
||||
|
||||
class TestPortBinding(base.TestOVNFunctionalBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPortBinding, self).setUp()
|
||||
def setUp(self, **kwargs):
|
||||
super().setUp(**kwargs)
|
||||
self.ovs_host = 'ovs-host'
|
||||
self.dpdk_host = 'dpdk-host'
|
||||
self.invalid_dpdk_host = 'invalid-host'
|
||||
self.insecure_host = 'insecure-host'
|
||||
self.smartnic_dpu_host = 'smartnic-dpu-host'
|
||||
self.smartnic_dpu_serial = 'fake-smartnic-dpu-serial'
|
||||
self.add_fake_chassis(self.ovs_host)
|
||||
self.add_fake_chassis(
|
||||
self.ovs_host,
|
||||
other_config={ovn_const.OVN_DATAPATH_TYPE: 'system'})
|
||||
self.add_fake_chassis(
|
||||
self.dpdk_host,
|
||||
other_config={'datapath-type': 'netdev',
|
||||
other_config={ovn_const.OVN_DATAPATH_TYPE: 'netdev',
|
||||
'iface-types': 'dummy,dummy-internal,dpdkvhostuser'})
|
||||
|
||||
self.add_fake_chassis(
|
||||
self.invalid_dpdk_host,
|
||||
other_config={'datapath-type': 'netdev',
|
||||
other_config={ovn_const.OVN_DATAPATH_TYPE: 'netdev',
|
||||
'iface-types': 'dummy,dummy-internal,geneve,vxlan'})
|
||||
self.add_fake_chassis(
|
||||
self.smartnic_dpu_host,
|
||||
other_config={ovn_const.OVN_CMS_OPTIONS: '{}={}'.format(
|
||||
ovn_const.CMS_OPT_CARD_SERIAL_NUMBER,
|
||||
self.smartnic_dpu_serial)})
|
||||
self.smartnic_dpu_serial),
|
||||
ovn_const.OVN_DATAPATH_TYPE: 'system'})
|
||||
self.n1 = self._make_network(self.fmt, 'n1', True)
|
||||
res = self._create_subnet(self.fmt, self.n1['network']['id'],
|
||||
'10.0.0.0/24')
|
||||
@ -152,9 +159,13 @@ class TestPortBinding(base.TestOVNFunctionalBase):
|
||||
self._verify_vif_details(port_id, self.dpdk_host, 'vhostuser',
|
||||
expected_vif_details)
|
||||
|
||||
expected_vif_details = copy.deepcopy(VHOSTUSER_VIF_DETAILS)
|
||||
expected_vif_details.pop('vhostuser_mode')
|
||||
expected_vif_details.pop('vhostuser_ovs_plug')
|
||||
expected_vif_details[portbindings.CAP_PORT_FILTER] = True
|
||||
port_id = self._create_or_update_port(hostname=self.invalid_dpdk_host)
|
||||
self._verify_vif_details(port_id, self.invalid_dpdk_host, 'ovs',
|
||||
OVS_VIF_DETAILS)
|
||||
expected_vif_details)
|
||||
|
||||
def test_port_binding_create_remote_managed_port(self):
|
||||
pci_vendor_info = 'fake-pci-vendor-info'
|
||||
@ -206,8 +217,12 @@ class TestPortBinding(base.TestOVNFunctionalBase):
|
||||
|
||||
port_id = self._create_or_update_port(port_id=port_id,
|
||||
hostname=self.invalid_dpdk_host)
|
||||
expected_vif_details = copy.deepcopy(VHOSTUSER_VIF_DETAILS)
|
||||
expected_vif_details.pop('vhostuser_mode')
|
||||
expected_vif_details.pop('vhostuser_ovs_plug')
|
||||
expected_vif_details[portbindings.CAP_PORT_FILTER] = True
|
||||
self._verify_vif_details(port_id, self.invalid_dpdk_host, 'ovs',
|
||||
OVS_VIF_DETAILS)
|
||||
expected_vif_details)
|
||||
|
||||
def test_port_binding_update_remote_managed_port(self):
|
||||
port_id = self._create_or_update_port(
|
||||
|
@ -181,6 +181,7 @@ class FakeOvsdbSbOvnIdl(object):
|
||||
self.get_extport_chassis_from_cms_options = mock.Mock(return_value=[])
|
||||
self.is_col_present = mock.Mock()
|
||||
self.is_col_present.return_value = False
|
||||
self.db_find = mock.MagicMock()
|
||||
self.db_set = mock.Mock()
|
||||
self.lookup = mock.MagicMock()
|
||||
self.chassis_list = mock.MagicMock()
|
||||
@ -856,7 +857,8 @@ class FakeChassis(object):
|
||||
def create(attrs=None, az_list=None, chassis_as_gw=False,
|
||||
bridge_mappings=None, rp_bandwidths=None,
|
||||
rp_inventory_defaults=None, rp_hypervisors=None,
|
||||
card_serial_number=None, chassis_as_extport=False):
|
||||
card_serial_number=None, chassis_as_extport=False,
|
||||
datapath_type=None):
|
||||
cms_opts = []
|
||||
if az_list:
|
||||
cms_opts.append("%s=%s" % (ovn_const.CMS_OPT_AVAILABILITY_ZONES,
|
||||
@ -901,6 +903,9 @@ class FakeChassis(object):
|
||||
if bridge_mappings:
|
||||
other_config['ovn-bridge-mappings'] = ','.join(bridge_mappings)
|
||||
|
||||
if datapath_type:
|
||||
other_config[ovn_const.OVN_DATAPATH_TYPE] = datapath_type
|
||||
|
||||
chassis_attrs = {
|
||||
'encaps': [],
|
||||
'external_ids': '',
|
||||
|
@ -46,6 +46,7 @@ from oslo_utils import uuidutils
|
||||
from ovsdbapp.backend.ovs_idl import idlutils
|
||||
from webob import exc
|
||||
|
||||
from neutron.common import _constants as n_const
|
||||
from neutron.common import config
|
||||
from neutron.common.ovn import acl as ovn_acl
|
||||
from neutron.common.ovn import constants as ovn_const
|
||||
@ -76,6 +77,7 @@ from neutron.tests.unit.plugins.ml2 import test_security_group
|
||||
OVN_PROFILE = ovn_const.OVN_PORT_BINDING_PROFILE
|
||||
CLASS_PLACEMENT_REPORT = ('neutron.services.placement_report.plugin.'
|
||||
'PlacementReportPlugin')
|
||||
DEFAULT_DP_TYPE = 'system' # For testing, we define "system" as default.
|
||||
|
||||
OvnRevNumberRow = collections.namedtuple(
|
||||
'OvnRevNumberRow', ['created_at'])
|
||||
@ -101,7 +103,7 @@ class MechDriverSetupBase(abc.ABC):
|
||||
self.mock_vp_parents = mock.patch.object(
|
||||
ovn_utils, 'get_virtual_port_parents', return_value=None).start()
|
||||
|
||||
def _add_chassis(self, nb_cfg, name=None):
|
||||
def _add_chassis_private(self, nb_cfg, name=None):
|
||||
chassis_private = mock.Mock()
|
||||
chassis_private.nb_cfg = nb_cfg
|
||||
chassis_private.uuid = uuid.uuid4()
|
||||
@ -109,26 +111,40 @@ class MechDriverSetupBase(abc.ABC):
|
||||
chassis_private.nb_cfg_timestamp = timeutils.utcnow_ts() * 1000
|
||||
return chassis_private
|
||||
|
||||
def _add_chassis_agent(self, nb_cfg, agent_type, chassis_private=None):
|
||||
chassis_private = chassis_private or self._add_chassis(nb_cfg)
|
||||
def _add_chassis(self, name, hostname, external_ids=None,
|
||||
other_config=None):
|
||||
external_ids = external_ids or {}
|
||||
other_config = other_config or {}
|
||||
return mock.Mock(name=name, hostname=hostname,
|
||||
external_ids=external_ids, other_config=other_config)
|
||||
|
||||
def _add_chassis_agent(self, nb_cfg, agent_type, chassis_private=None,
|
||||
hostname=None):
|
||||
chassis_private = chassis_private or self._add_chassis_private(nb_cfg)
|
||||
hostname = hostname or chassis_private.name + '_host'
|
||||
if hasattr(chassis_private, 'nb_cfg_timestamp') and isinstance(
|
||||
chassis_private.nb_cfg_timestamp, mock.Mock):
|
||||
del chassis_private.nb_cfg_timestamp
|
||||
chassis_private.external_ids = {}
|
||||
chassis_private.other_config = {}
|
||||
chassis_private.external_ids = {
|
||||
ovn_const.OVN_AGENT_OVN_BRIDGE: n_const.DEFAULT_BR_INT,
|
||||
ovn_const.OVN_DATAPATH_TYPE: DEFAULT_DP_TYPE,
|
||||
}
|
||||
if agent_type == ovn_const.OVN_METADATA_AGENT:
|
||||
chassis_private.external_ids.update({
|
||||
ovn_const.OVN_AGENT_METADATA_SB_CFG_KEY: nb_cfg,
|
||||
ovn_const.OVN_AGENT_METADATA_ID_KEY: str(uuid.uuid4())})
|
||||
chassis_private.chassis = [chassis_private]
|
||||
chassis_private.chassis = [self._add_chassis(chassis_private.name,
|
||||
hostname)]
|
||||
return neutron_agent.AgentCache().update(agent_type, chassis_private)
|
||||
|
||||
def _add_agent(self, name, nb_cfg_offset=0):
|
||||
def _add_agent(self, name, nb_cfg_offset=0, hostname=None):
|
||||
hostname = hostname or name + '_host'
|
||||
nb_cfg = 5
|
||||
self.mech_driver.nb_ovn.nb_global.nb_cfg = nb_cfg + nb_cfg_offset
|
||||
chassis = self._add_chassis(nb_cfg, name=name)
|
||||
chassis_private = self._add_chassis_private(nb_cfg, name=name)
|
||||
return self._add_chassis_agent(
|
||||
nb_cfg, ovn_const.OVN_CONTROLLER_AGENT, chassis)
|
||||
nb_cfg, ovn_const.OVN_CONTROLLER_AGENT,
|
||||
chassis_private=chassis_private, hostname=hostname)
|
||||
|
||||
|
||||
class TestOVNMechanismDriverBase(MechDriverSetupBase,
|
||||
@ -1242,6 +1258,9 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
self._test_bind_port_failed([])
|
||||
|
||||
def _test_bind_port(self, fake_segments):
|
||||
fake_chassis = fakes.FakeChassis.create(datapath_type=DEFAULT_DP_TYPE)
|
||||
self.sb_ovn.db_find.return_value.execute.return_value = [
|
||||
{'other_config': fake_chassis.other_config}]
|
||||
fake_port = fakes.FakePort.create_one_port().info()
|
||||
fake_host = 'host'
|
||||
fake_port_context = fakes.FakePortContext(
|
||||
@ -1250,12 +1269,18 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
neutron_agent.AgentCache().get_agents.assert_called_once_with(
|
||||
{'host': fake_host,
|
||||
'agent_type': ovn_const.OVN_CONTROLLER_TYPES})
|
||||
fake_port_context.set_binding.assert_called_once_with(
|
||||
fake_segments[0]['id'],
|
||||
portbindings.VIF_TYPE_OVS,
|
||||
vif_details = copy.deepcopy(
|
||||
self.mech_driver.vif_details[portbindings.VIF_TYPE_OVS])
|
||||
vif_details[
|
||||
portbindings.VIF_DETAILS_BRIDGE_NAME] = n_const.DEFAULT_BR_INT
|
||||
vif_details[portbindings.OVS_DATAPATH_TYPE] = DEFAULT_DP_TYPE
|
||||
fake_port_context.set_binding.assert_called_once_with(
|
||||
fake_segments[0]['id'], portbindings.VIF_TYPE_OVS, vif_details)
|
||||
|
||||
def _test_bind_port_sriov(self, fake_segments):
|
||||
fake_chassis = fakes.FakeChassis.create(datapath_type=DEFAULT_DP_TYPE)
|
||||
self.sb_ovn.db_find.return_value.execute.return_value = [
|
||||
{'other_config': fake_chassis.other_config}]
|
||||
fake_port = fakes.FakePort.create_one_port(
|
||||
attrs={'binding:vnic_type': 'direct',
|
||||
'binding:profile': {
|
||||
@ -1268,12 +1293,18 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
neutron_agent.AgentCache().get_agents.assert_called_once_with(
|
||||
{'host': fake_host,
|
||||
'agent_type': ovn_const.OVN_CONTROLLER_TYPES})
|
||||
fake_port_context.set_binding.assert_called_once_with(
|
||||
fake_segments[0]['id'],
|
||||
portbindings.VIF_TYPE_OVS,
|
||||
vif_details = copy.deepcopy(
|
||||
self.mech_driver.vif_details[portbindings.VIF_TYPE_OVS])
|
||||
vif_details[
|
||||
portbindings.VIF_DETAILS_BRIDGE_NAME] = n_const.DEFAULT_BR_INT
|
||||
vif_details[portbindings.OVS_DATAPATH_TYPE] = DEFAULT_DP_TYPE
|
||||
fake_port_context.set_binding.assert_called_once_with(
|
||||
fake_segments[0]['id'], portbindings.VIF_TYPE_OVS, vif_details)
|
||||
|
||||
def _test_bind_port_virtio_forwarder(self, fake_segments):
|
||||
fake_chassis = fakes.FakeChassis.create(datapath_type=DEFAULT_DP_TYPE)
|
||||
self.sb_ovn.db_find.return_value.execute.return_value = [
|
||||
{'other_config': fake_chassis.other_config}]
|
||||
fake_port = fakes.FakePort.create_one_port(
|
||||
attrs={'binding:vnic_type': 'virtio-forwarder'}).info()
|
||||
fake_host = 'host'
|
||||
@ -1281,11 +1312,15 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
fake_port, fake_host, fake_segments)
|
||||
self.mech_driver.bind_port(fake_port_context)
|
||||
|
||||
vif_details = self.mech_driver.\
|
||||
vif_details[portbindings.VIF_TYPE_AGILIO_OVS]
|
||||
vif_details.update({"vhostuser_socket": ovn_utils.ovn_vhu_sockpath(
|
||||
ovn_conf.get_ovn_vhost_sock_dir(), fake_port['id'])})
|
||||
vif_details.update({"vhostuser_mode": "client"})
|
||||
vif_details = copy.deepcopy(
|
||||
self.mech_driver.vif_details[portbindings.VIF_TYPE_AGILIO_OVS])
|
||||
vif_details.update({
|
||||
'vhostuser_socket': ovn_utils.ovn_vhu_sockpath(
|
||||
ovn_conf.get_ovn_vhost_sock_dir(), fake_port['id']),
|
||||
'vhostuser_mode': 'client',
|
||||
portbindings.VIF_DETAILS_BRIDGE_NAME: n_const.DEFAULT_BR_INT,
|
||||
portbindings.OVS_DATAPATH_TYPE: DEFAULT_DP_TYPE,
|
||||
})
|
||||
|
||||
neutron_agent.AgentCache().get_agents.assert_called_once_with(
|
||||
{'host': fake_host,
|
||||
@ -1312,6 +1347,9 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
attrs={'hostname': fake_smartnic_dpu},
|
||||
card_serial_number=fake_serial)
|
||||
|
||||
fake_chassis = fakes.FakeChassis.create(datapath_type=DEFAULT_DP_TYPE)
|
||||
self.sb_ovn.db_find.return_value.execute.return_value = [
|
||||
{'other_config': fake_chassis.other_config}]
|
||||
self.sb_ovn.get_chassis_by_card_serial_from_cms_options.\
|
||||
return_value = ch_smartnic_dpu
|
||||
fake_host = 'host'
|
||||
@ -1321,12 +1359,18 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
neutron_agent.AgentCache().get_agents.assert_called_once_with(
|
||||
{'host': fake_smartnic_dpu,
|
||||
'agent_type': ovn_const.OVN_CONTROLLER_TYPES})
|
||||
fake_port_context.set_binding.assert_called_once_with(
|
||||
fake_segments[0]['id'],
|
||||
portbindings.VIF_TYPE_OVS,
|
||||
vif_details = copy.deepcopy(
|
||||
self.mech_driver.vif_details[portbindings.VIF_TYPE_OVS])
|
||||
vif_details[
|
||||
portbindings.VIF_DETAILS_BRIDGE_NAME] = n_const.DEFAULT_BR_INT
|
||||
vif_details[portbindings.OVS_DATAPATH_TYPE] = DEFAULT_DP_TYPE
|
||||
fake_port_context.set_binding.assert_called_once_with(
|
||||
fake_segments[0]['id'], portbindings.VIF_TYPE_OVS, vif_details)
|
||||
|
||||
def test_bind_port_vdpa(self):
|
||||
fake_chassis = fakes.FakeChassis.create(datapath_type=DEFAULT_DP_TYPE)
|
||||
self.sb_ovn.db_find.return_value.execute.return_value = [
|
||||
{'other_config': fake_chassis.other_config}]
|
||||
segment_attrs = {'network_type': 'geneve',
|
||||
'physical_network': None,
|
||||
'segmentation_id': 1023}
|
||||
@ -1343,10 +1387,13 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
neutron_agent.AgentCache().get_agents.assert_called_once_with(
|
||||
{'host': fake_host,
|
||||
'agent_type': ovn_const.OVN_CONTROLLER_TYPES})
|
||||
fake_port_context.set_binding.assert_called_once_with(
|
||||
fake_segments[0]['id'],
|
||||
portbindings.VIF_TYPE_OVS,
|
||||
vif_details = copy.deepcopy(
|
||||
self.mech_driver.vif_details[portbindings.VIF_TYPE_OVS])
|
||||
vif_details[
|
||||
portbindings.VIF_DETAILS_BRIDGE_NAME] = n_const.DEFAULT_BR_INT
|
||||
vif_details[portbindings.OVS_DATAPATH_TYPE] = DEFAULT_DP_TYPE
|
||||
fake_port_context.set_binding.assert_called_once_with(
|
||||
fake_segments[0]['id'], portbindings.VIF_TYPE_OVS, vif_details)
|
||||
|
||||
def test_bind_port_geneve(self):
|
||||
segment_attrs = {'network_type': 'geneve',
|
||||
@ -2374,7 +2421,7 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
mock_notify_dhcp.assert_called_with(fake_port['id'])
|
||||
|
||||
def test_agent_alive_true(self):
|
||||
chassis_private = self._add_chassis(5)
|
||||
chassis_private = self._add_chassis_private(5)
|
||||
for agent_type in (ovn_const.OVN_CONTROLLER_AGENT,
|
||||
ovn_const.OVN_METADATA_AGENT):
|
||||
self.mech_driver.nb_ovn.nb_global.nb_cfg = 5
|
||||
@ -2386,7 +2433,7 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
# Agent should be reported as alive when the nb_cfg delta is 1
|
||||
# even if the last update time was old enough.
|
||||
nb_cfg = 5
|
||||
chassis_private = self._add_chassis(nb_cfg)
|
||||
chassis_private = self._add_chassis_private(nb_cfg)
|
||||
for agent_type in (ovn_const.OVN_CONTROLLER_AGENT,
|
||||
ovn_const.OVN_METADATA_AGENT):
|
||||
self.mech_driver.nb_ovn.nb_global.nb_cfg = nb_cfg + 1
|
||||
@ -2401,7 +2448,7 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
|
||||
def test_agent_alive_not_timed_out(self):
|
||||
nb_cfg = 3
|
||||
chassis_private = self._add_chassis(nb_cfg)
|
||||
chassis_private = self._add_chassis_private(nb_cfg)
|
||||
for agent_type in (ovn_const.OVN_CONTROLLER_AGENT,
|
||||
ovn_const.OVN_METADATA_AGENT):
|
||||
self.mech_driver.nb_ovn.nb_global.nb_cfg = nb_cfg + 2
|
||||
@ -2412,7 +2459,7 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
|
||||
def test_agent_alive_timed_out(self):
|
||||
nb_cfg = 3
|
||||
chassis_private = self._add_chassis(nb_cfg)
|
||||
chassis_private = self._add_chassis_private(nb_cfg)
|
||||
for agent_type in (ovn_const.OVN_CONTROLLER_AGENT,
|
||||
ovn_const.OVN_METADATA_AGENT):
|
||||
self.mech_driver.nb_ovn.nb_global.nb_cfg = nb_cfg + 2
|
||||
@ -2427,7 +2474,7 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
|
||||
def test_agent_with_nb_cfg_timestamp_timeout(self):
|
||||
nb_cfg = 3
|
||||
chassis_private = self._add_chassis(nb_cfg)
|
||||
chassis_private = self._add_chassis_private(nb_cfg)
|
||||
|
||||
self.mech_driver.nb_ovn.nb_global.nb_cfg = nb_cfg + 2
|
||||
updated_at = (timeutils.utcnow_ts() - cfg.CONF.agent_down_time - 1
|
||||
@ -2441,7 +2488,7 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
|
||||
def test_agent_with_nb_cfg_timestamp_not_timeout(self):
|
||||
nb_cfg = 3
|
||||
chassis_private = self._add_chassis(nb_cfg)
|
||||
chassis_private = self._add_chassis_private(nb_cfg)
|
||||
|
||||
self.mech_driver.nb_ovn.nb_global.nb_cfg = nb_cfg + 2
|
||||
updated_at = timeutils.utcnow_ts() * 1000
|
||||
|
@ -11,7 +11,7 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
from unittest import mock
|
||||
|
||||
from neutron_lib.api.definitions import portbindings as pb
|
||||
@ -21,6 +21,7 @@ from neutron_lib.db import api as db_api
|
||||
from neutron_lib import exceptions
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from neutron.common import _constants as n_const
|
||||
from neutron.db.models.plugins.ml2 import geneveallocation
|
||||
from neutron.db.models.plugins.ml2 import vxlanallocation
|
||||
from neutron.objects import ports as port_obj
|
||||
@ -48,11 +49,12 @@ class TestMigrateNeutronDatabaseToOvn(
|
||||
|
||||
for vif_details in vif_details_list:
|
||||
port = self._make_port(self.fmt, network_id)['port']
|
||||
port_o = port_obj.PortBinding.get_object(
|
||||
ctx, port_id=port['id'], host='')
|
||||
port_o.vif_type = 'ovs'
|
||||
port_o.vif_details = vif_details
|
||||
port_o.update()
|
||||
with db_api.CONTEXT_WRITER.using(ctx):
|
||||
port_o = port_obj.PortBinding.get_object(
|
||||
ctx, port_id=port['id'], host='')
|
||||
port_o.vif_type = 'ovs'
|
||||
port_o.vif_details = vif_details
|
||||
port_o.update()
|
||||
|
||||
for i in range(1, 4):
|
||||
port = self._make_port(self.fmt, network_id)['port']
|
||||
@ -152,14 +154,10 @@ class TestMigrateNeutronDatabaseToOvn(
|
||||
{"foo": "bar"},
|
||||
{},
|
||||
]
|
||||
expected_vif_details = [
|
||||
{pb.CAP_PORT_FILTER: "true",
|
||||
pb.OVS_HYBRID_PLUG: "true",
|
||||
pb.VIF_DETAILS_CONNECTIVITY: pb.CONNECTIVITY_L2},
|
||||
{pb.CAP_PORT_FILTER: "true"},
|
||||
{"foo": "bar"},
|
||||
{},
|
||||
]
|
||||
expected_vif_details = copy.deepcopy(vif_details_list)
|
||||
for vif_detail in expected_vif_details:
|
||||
vif_detail[pb.VIF_DETAILS_BRIDGE_NAME] = n_const.DEFAULT_BR_INT
|
||||
expected_vif_details.append({})
|
||||
|
||||
self._create_ml2_ovs_test_resources(vif_details_list)
|
||||
db_migration.migrate_neutron_database_to_ovn()
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
[`bug 2045889 <https://bugs.launchpad.net/neutron/+bug/2045889>`_]
|
||||
The ports bound to ML2/OVN now contain the OVS bridge name and datapath
|
||||
type in the VIF details dictionary. NOTE: in the ML2/OVS to ML2/OVN
|
||||
migration, the local host OVN bridge (integration bridge) per port is not
|
||||
known; "br-int" will be used by default (that value is rarely changed).
|
Loading…
Reference in New Issue
Block a user