Merge "[OVN] Add vnic_type and binding profile capabilities to LSP info"
This commit is contained in:
commit
7fa5346e05
@ -26,6 +26,8 @@ OVN_NETWORK_MTU_EXT_ID_KEY = 'neutron:mtu'
|
||||
OVN_PORT_NAME_EXT_ID_KEY = 'neutron:port_name'
|
||||
OVN_PORT_EXT_ID_KEY = 'neutron:port_id'
|
||||
OVN_PORT_FIP_EXT_ID_KEY = 'neutron:port_fip'
|
||||
OVN_PORT_BP_CAPABILITIES_KEY = 'neutron:port_capabilities'
|
||||
OVN_PORT_VNIC_TYPE_KEY = 'neutron:vnic_type'
|
||||
OVN_ROUTER_NAME_EXT_ID_KEY = 'neutron:router_name'
|
||||
OVN_ROUTER_ID_EXT_ID_KEY = 'neutron:router_id'
|
||||
OVN_AZ_HINTS_EXT_ID_KEY = 'neutron:availability_zone_hints'
|
||||
|
@ -55,6 +55,8 @@ AddrPairsDiff = collections.namedtuple(
|
||||
|
||||
PortExtraDHCPValidation = collections.namedtuple(
|
||||
'PortExtraDHCPValidation', ['failed', 'invalid_ipv4', 'invalid_ipv6'])
|
||||
BPInfo = collections.namedtuple(
|
||||
'BPInfo', ['bp_param', 'vnic_type', 'capabilities'])
|
||||
|
||||
|
||||
class OvsdbClientCommand(object):
|
||||
@ -309,10 +311,17 @@ def is_security_groups_enabled(port):
|
||||
|
||||
|
||||
def validate_and_get_data_from_binding_profile(port):
|
||||
"""Validate the port binding profile
|
||||
|
||||
:param port: (dict) Neutron port dictionary.
|
||||
:returns: (namedtuple BPInfo: dict, string, list) a tuple with the
|
||||
dictionary of the port profile, the VNIC type and a list of port
|
||||
capabilities.
|
||||
"""
|
||||
if (constants.OVN_PORT_BINDING_PROFILE not in port or
|
||||
not validators.is_attr_set(
|
||||
port[constants.OVN_PORT_BINDING_PROFILE])):
|
||||
return {}
|
||||
BPInfo({}, None, [])
|
||||
param_set = {}
|
||||
param_dict = {}
|
||||
vnic_type = port.get(portbindings.VNIC_TYPE, portbindings.VNIC_NORMAL)
|
||||
@ -354,7 +363,7 @@ def validate_and_get_data_from_binding_profile(port):
|
||||
break
|
||||
|
||||
if not param_dict:
|
||||
return {}
|
||||
return BPInfo({}, vnic_type, capabilities)
|
||||
|
||||
# With this example param_set:
|
||||
#
|
||||
@ -406,7 +415,7 @@ def validate_and_get_data_from_binding_profile(port):
|
||||
'an integer between 0 and 4095, inclusive') % tag
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
|
||||
return param_dict
|
||||
return BPInfo(param_dict, vnic_type, capabilities)
|
||||
|
||||
|
||||
def is_dhcp_options_ignored(subnet):
|
||||
|
@ -120,6 +120,14 @@ class PortBinding(PortBindingBase):
|
||||
cls.db_model.status == constants.INACTIVE)
|
||||
return context.session.query(cls.db_model).filter(_filter).all()
|
||||
|
||||
@classmethod
|
||||
@db_api.CONTEXT_READER
|
||||
def get_port_binding_by_vnic_type(cls, context, vnic_type):
|
||||
"""Returns the port binding filtering by VNIC type."""
|
||||
query = context.session.query(cls.db_model)
|
||||
query = query.filter(cls.db_model.vnic_type == vnic_type)
|
||||
return query.all()
|
||||
|
||||
|
||||
@base.NeutronObjectRegistry.register
|
||||
class DistributedPortBinding(PortBindingBase):
|
||||
|
@ -28,6 +28,7 @@ from neutron_lib.db import api as db_api
|
||||
from neutron_lib import exceptions as n_exc
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import timeutils
|
||||
from ovsdbapp.backend.ovs_idl import event as row_event
|
||||
|
||||
@ -918,6 +919,38 @@ class DBInconsistenciesPeriodics(SchemaAwarePeriodicsBase):
|
||||
|
||||
raise periodics.NeverAgain()
|
||||
|
||||
# TODO(ralonsoh): Remove this in the Antelope+4 cycle
|
||||
@periodics.periodic(spacing=600, run_immediately=True)
|
||||
def add_vnic_type_and_pb_capabilities_to_lsp(self):
|
||||
"""Add the port VNIC type and port binding capabilities to the LSP.
|
||||
|
||||
This is needed to know if a port has hardware offload capabilities.
|
||||
This method is only updating those ports with VNIC type direct, in
|
||||
order to minimize the load impact of this method when updating the OVN
|
||||
database. Within the patch that adds this maintenance method, it has
|
||||
been added to the LSP the VNIC type and the port binding capabilities.
|
||||
To implement LP#1998608, only direct ports are needed.
|
||||
"""
|
||||
if not self.has_lock:
|
||||
return
|
||||
|
||||
port_bindings = ports_obj.PortBinding.get_port_binding_by_vnic_type(
|
||||
n_context.get_admin_context(), portbindings.VNIC_DIRECT)
|
||||
with self._nb_idl.transaction(check_error=True) as txn:
|
||||
for pb in port_bindings:
|
||||
profile = jsonutils.loads(pb.profile)
|
||||
capabilities = profile.get(ovn_const.PORT_CAP_PARAM, [])
|
||||
external_ids = {
|
||||
ovn_const.OVN_PORT_VNIC_TYPE_KEY: portbindings.VNIC_DIRECT,
|
||||
ovn_const.OVN_PORT_BP_CAPABILITIES_KEY:
|
||||
';'.join(capabilities)
|
||||
}
|
||||
txn.add(self._nb_idl.set_lswitch_port(
|
||||
lport_name=pb.port_id, if_exists=True,
|
||||
external_ids=external_ids))
|
||||
|
||||
raise periodics.NeverAgain()
|
||||
|
||||
|
||||
class HashRingHealthCheckPeriodics(object):
|
||||
|
||||
|
@ -73,6 +73,8 @@ OvnPortInfo = collections.namedtuple(
|
||||
"security_group_ids",
|
||||
"address4_scope_id",
|
||||
"address6_scope_id",
|
||||
"vnic_type",
|
||||
"capabilities",
|
||||
],
|
||||
)
|
||||
|
||||
@ -263,18 +265,18 @@ class OVNClient(object):
|
||||
return port_context.host if port_context else port.get(
|
||||
portbindings.HOST_ID, '')
|
||||
|
||||
binding_prof = utils.validate_and_get_data_from_binding_profile(port)
|
||||
if ovn_const.VIF_DETAILS_CARD_SERIAL_NUMBER in binding_prof:
|
||||
bp_info = (
|
||||
utils.validate_and_get_data_from_binding_profile(port))
|
||||
if ovn_const.VIF_DETAILS_CARD_SERIAL_NUMBER in bp_info.bp_param:
|
||||
return self._sb_idl.get_chassis_by_card_serial_from_cms_options(
|
||||
binding_prof[
|
||||
bp_info.bp_param[
|
||||
ovn_const.VIF_DETAILS_CARD_SERIAL_NUMBER]).hostname
|
||||
return ''
|
||||
|
||||
def _get_port_options(self, port):
|
||||
context = n_context.get_admin_context()
|
||||
binding_prof = utils.validate_and_get_data_from_binding_profile(port)
|
||||
vnic_type = port.get(portbindings.VNIC_TYPE, portbindings.VNIC_NORMAL)
|
||||
vtep_physical_switch = binding_prof.get('vtep-physical-switch')
|
||||
bp_info = utils.validate_and_get_data_from_binding_profile(port)
|
||||
vtep_physical_switch = bp_info.bp_param.get('vtep-physical-switch')
|
||||
|
||||
port_type = ''
|
||||
cidrs = ''
|
||||
@ -283,7 +285,7 @@ class OVNClient(object):
|
||||
dhcpv4_options = self._get_port_dhcp_options(port, const.IP_VERSION_4)
|
||||
dhcpv6_options = self._get_port_dhcp_options(port, const.IP_VERSION_6)
|
||||
if vtep_physical_switch:
|
||||
vtep_logical_switch = binding_prof.get('vtep-logical-switch')
|
||||
vtep_logical_switch = bp_info.bp_param.get('vtep-logical-switch')
|
||||
port_type = 'vtep'
|
||||
options = {'vtep-physical-switch': vtep_physical_switch,
|
||||
'vtep-logical-switch': vtep_logical_switch}
|
||||
@ -293,8 +295,8 @@ class OVNClient(object):
|
||||
port_security = []
|
||||
else:
|
||||
options = {}
|
||||
parent_name = binding_prof.get('parent_name', [])
|
||||
tag = binding_prof.get('tag', [])
|
||||
parent_name = bp_info.bp_param.get('parent_name', [])
|
||||
tag = bp_info.bp_param.get('tag', [])
|
||||
address = port['mac_address']
|
||||
|
||||
ip_subnets = port.get('fixed_ips', [])
|
||||
@ -394,8 +396,8 @@ class OVNClient(object):
|
||||
# HA Chassis Group will bind the port to the highest
|
||||
# priority Chassis
|
||||
if port_type != ovn_const.LSP_TYPE_EXTERNAL:
|
||||
if (vnic_type == portbindings.VNIC_REMOTE_MANAGED and
|
||||
ovn_const.VIF_DETAILS_PF_MAC_ADDRESS in binding_prof):
|
||||
if (bp_info.vnic_type == portbindings.VNIC_REMOTE_MANAGED and
|
||||
ovn_const.VIF_DETAILS_PF_MAC_ADDRESS in bp_info.bp_param):
|
||||
port_net = self._plugin.get_network(
|
||||
context, port['network_id'])
|
||||
options.update({
|
||||
@ -403,10 +405,10 @@ class OVNClient(object):
|
||||
ovn_const.LSP_OPTIONS_VIF_PLUG_MTU_REQUEST_KEY: str(
|
||||
port_net['mtu']),
|
||||
ovn_const.LSP_OPTIONS_VIF_PLUG_REPRESENTOR_PF_MAC_KEY: (
|
||||
binding_prof.get(
|
||||
bp_info.bp_param.get(
|
||||
ovn_const.VIF_DETAILS_PF_MAC_ADDRESS)),
|
||||
ovn_const.LSP_OPTIONS_VIF_PLUG_REPRESENTOR_VF_NUM_KEY: str(
|
||||
binding_prof.get(ovn_const.VIF_DETAILS_VF_NUM))})
|
||||
bp_info.bp_param.get(ovn_const.VIF_DETAILS_VF_NUM))})
|
||||
chassis = self.determine_bind_host(port)
|
||||
if chassis:
|
||||
# If OVN supports multi-chassis port bindings, use it for live
|
||||
@ -440,7 +442,8 @@ class OVNClient(object):
|
||||
return OvnPortInfo(port_type, options, addresses, port_security,
|
||||
parent_name, tag, dhcpv4_options, dhcpv6_options,
|
||||
cidrs.strip(), device_owner, sg_ids,
|
||||
address4_scope_id, address6_scope_id
|
||||
address4_scope_id, address6_scope_id,
|
||||
bp_info.vnic_type, bp_info.capabilities
|
||||
)
|
||||
|
||||
def sync_ha_chassis_group(self, context, network_id, txn):
|
||||
@ -533,23 +536,25 @@ class OVNClient(object):
|
||||
|
||||
def get_external_ids_from_port(self, port):
|
||||
port_info = self._get_port_options(port)
|
||||
external_ids = {ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port['name'],
|
||||
ovn_const.OVN_DEVID_EXT_ID_KEY: port['device_id'],
|
||||
ovn_const.OVN_PROJID_EXT_ID_KEY: port['project_id'],
|
||||
ovn_const.OVN_CIDRS_EXT_ID_KEY: port_info.cidrs,
|
||||
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
port_info.device_owner,
|
||||
ovn_const.OVN_SUBNET_POOL_EXT_ADDR_SCOPE4_KEY:
|
||||
port_info.address4_scope_id,
|
||||
ovn_const.OVN_SUBNET_POOL_EXT_ADDR_SCOPE6_KEY:
|
||||
port_info.address6_scope_id,
|
||||
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY:
|
||||
utils.ovn_name(port['network_id']),
|
||||
ovn_const.OVN_SG_IDS_EXT_ID_KEY:
|
||||
port_info.security_group_ids,
|
||||
ovn_const.OVN_REV_NUM_EXT_ID_KEY: str(
|
||||
utils.get_revision_number(
|
||||
port, ovn_const.TYPE_PORTS))}
|
||||
external_ids = {
|
||||
ovn_const.OVN_PORT_NAME_EXT_ID_KEY: port['name'],
|
||||
ovn_const.OVN_DEVID_EXT_ID_KEY: port['device_id'],
|
||||
ovn_const.OVN_PROJID_EXT_ID_KEY: port['project_id'],
|
||||
ovn_const.OVN_CIDRS_EXT_ID_KEY: port_info.cidrs,
|
||||
ovn_const.OVN_DEVICE_OWNER_EXT_ID_KEY: port_info.device_owner,
|
||||
ovn_const.OVN_SUBNET_POOL_EXT_ADDR_SCOPE4_KEY:
|
||||
port_info.address4_scope_id,
|
||||
ovn_const.OVN_SUBNET_POOL_EXT_ADDR_SCOPE6_KEY:
|
||||
port_info.address6_scope_id,
|
||||
ovn_const.OVN_NETWORK_NAME_EXT_ID_KEY:
|
||||
utils.ovn_name(port['network_id']),
|
||||
ovn_const.OVN_SG_IDS_EXT_ID_KEY: port_info.security_group_ids,
|
||||
ovn_const.OVN_REV_NUM_EXT_ID_KEY: str(utils.get_revision_number(
|
||||
port, ovn_const.TYPE_PORTS)),
|
||||
ovn_const.OVN_PORT_VNIC_TYPE_KEY: port_info.vnic_type,
|
||||
ovn_const.OVN_PORT_BP_CAPABILITIES_KEY:
|
||||
';'.join(port_info.capabilities),
|
||||
}
|
||||
return port_info, external_ids
|
||||
|
||||
def create_port(self, context, port):
|
||||
|
@ -588,8 +588,8 @@ class TestValidateAndGetDataFromBindingProfile(base.BaseTestCase):
|
||||
'parent_name': 'fake-parent-port-uuid',
|
||||
'tag': 42
|
||||
}
|
||||
self.assertDictEqual(
|
||||
expect,
|
||||
self.assertEqual(
|
||||
utils.BPInfo(expect, portbindings.VNIC_NORMAL, []),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{constants.OVN_PORT_BINDING_PROFILE: expect}))
|
||||
|
||||
@ -597,8 +597,8 @@ class TestValidateAndGetDataFromBindingProfile(base.BaseTestCase):
|
||||
'vtep-physical-switch': 'fake-physical-switch-uuid',
|
||||
'vtep-logical-switch': 'fake-logical-switch-uuid',
|
||||
}
|
||||
self.assertDictEqual(
|
||||
expect,
|
||||
self.assertEqual(
|
||||
utils.BPInfo(expect, portbindings.VNIC_NORMAL, []),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{constants.OVN_PORT_BINDING_PROFILE: expect}))
|
||||
|
||||
@ -611,8 +611,9 @@ class TestValidateAndGetDataFromBindingProfile(base.BaseTestCase):
|
||||
}
|
||||
expect = binding_profile.copy()
|
||||
del(expect[constants.PORT_CAP_PARAM])
|
||||
self.assertDictEqual(
|
||||
expect,
|
||||
self.assertEqual(
|
||||
utils.BPInfo(expect, portbindings.VNIC_DIRECT,
|
||||
[constants.PORT_CAP_SWITCHDEV]),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{portbindings.VNIC_TYPE: portbindings.VNIC_DIRECT,
|
||||
constants.OVN_PORT_BINDING_PROFILE: binding_profile}))
|
||||
@ -626,8 +627,9 @@ class TestValidateAndGetDataFromBindingProfile(base.BaseTestCase):
|
||||
}
|
||||
expect = binding_profile.copy()
|
||||
del(expect[constants.PORT_CAP_PARAM])
|
||||
self.assertDictEqual(
|
||||
expect,
|
||||
self.assertEqual(
|
||||
utils.BPInfo(expect, portbindings.VNIC_DIRECT,
|
||||
[constants.PORT_CAP_SWITCHDEV]),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{portbindings.VNIC_TYPE: portbindings.VNIC_DIRECT,
|
||||
constants.OVN_PORT_BINDING_PROFILE: binding_profile}))
|
||||
@ -640,11 +642,11 @@ class TestValidateAndGetDataFromBindingProfile(base.BaseTestCase):
|
||||
'pf_mac_address': '00:53:00:00:00:42',
|
||||
'vf_num': 42,
|
||||
}
|
||||
self.assertDictEqual(
|
||||
self.assertEqual(
|
||||
utils.BPInfo(expect, portbindings.VNIC_REMOTE_MANAGED, []),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{portbindings.VNIC_TYPE: portbindings.VNIC_REMOTE_MANAGED,
|
||||
constants.OVN_PORT_BINDING_PROFILE: expect}),
|
||||
expect)
|
||||
constants.OVN_PORT_BINDING_PROFILE: expect}))
|
||||
|
||||
def test_valid_input_surplus_keys(self):
|
||||
# Confirm that extra keys are allowed
|
||||
@ -658,8 +660,9 @@ class TestValidateAndGetDataFromBindingProfile(base.BaseTestCase):
|
||||
expect = binding_profile.copy()
|
||||
del(expect[constants.PORT_CAP_PARAM])
|
||||
del(expect['optional_information_provided_by_nova'])
|
||||
self.assertDictEqual(
|
||||
expect,
|
||||
self.assertEqual(
|
||||
utils.BPInfo(expect, portbindings.VNIC_DIRECT,
|
||||
[constants.PORT_CAP_SWITCHDEV]),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{portbindings.VNIC_TYPE: portbindings.VNIC_DIRECT,
|
||||
constants.OVN_PORT_BINDING_PROFILE: binding_profile}))
|
||||
@ -667,7 +670,7 @@ class TestValidateAndGetDataFromBindingProfile(base.BaseTestCase):
|
||||
def test_unknown_profile_items_pruned(self):
|
||||
# Confirm that unknown profile items are pruned
|
||||
self.assertEqual(
|
||||
{},
|
||||
utils.BPInfo({}, portbindings.VNIC_NORMAL, []),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{constants.OVN_PORT_BINDING_PROFILE: {
|
||||
'unknown-key': 'unknown-data'}}))
|
||||
@ -676,16 +679,16 @@ class TestValidateAndGetDataFromBindingProfile(base.BaseTestCase):
|
||||
expect = {
|
||||
'key': 'value',
|
||||
}
|
||||
self.assertDictEqual(
|
||||
expect,
|
||||
self.assertEqual(
|
||||
utils.BPInfo(expect, self.VNIC_FAKE_NORMAL, []),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{portbindings.VNIC_TYPE: self.VNIC_FAKE_NORMAL,
|
||||
constants.OVN_PORT_BINDING_PROFILE: expect}))
|
||||
expect = {
|
||||
'key': None,
|
||||
}
|
||||
self.assertDictEqual(
|
||||
expect,
|
||||
self.assertEqual(
|
||||
utils.BPInfo(expect, self.VNIC_FAKE_NORMAL, []),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{portbindings.VNIC_TYPE: self.VNIC_FAKE_NORMAL,
|
||||
constants.OVN_PORT_BINDING_PROFILE: expect}))
|
||||
@ -706,17 +709,17 @@ class TestValidateAndGetDataFromBindingProfile(base.BaseTestCase):
|
||||
'other_key': 'value',
|
||||
}
|
||||
# This param set is valid for VNIC_FAKE_NORMAL with 'other_key' pruned.
|
||||
expect = binding_profile.copy()
|
||||
del(expect['other_key'])
|
||||
self.assertDictEqual(
|
||||
expect,
|
||||
expected_bp = binding_profile.copy()
|
||||
del(expected_bp['other_key'])
|
||||
self.assertEqual(
|
||||
utils.BPInfo(expected_bp, self.VNIC_FAKE_NORMAL, []),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{portbindings.VNIC_TYPE: self.VNIC_FAKE_NORMAL,
|
||||
constants.OVN_PORT_BINDING_PROFILE: binding_profile}))
|
||||
# It is valid for VNIC_FAKE_OTHER
|
||||
expect = binding_profile.copy()
|
||||
self.assertDictEqual(
|
||||
expect,
|
||||
expected_bp = binding_profile.copy()
|
||||
self.assertEqual(
|
||||
utils.BPInfo(expected_bp, self.VNIC_FAKE_OTHER, []),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{portbindings.VNIC_TYPE: self.VNIC_FAKE_OTHER,
|
||||
constants.OVN_PORT_BINDING_PROFILE: binding_profile}))
|
||||
@ -744,7 +747,7 @@ class TestValidateAndGetDataFromBindingProfile(base.BaseTestCase):
|
||||
'third_key': 'value',
|
||||
}
|
||||
self.assertEqual(
|
||||
{},
|
||||
utils.BPInfo({}, self.VNIC_FAKE_OTHER, ['fake-capability']),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{portbindings.VNIC_TYPE: self.VNIC_FAKE_OTHER,
|
||||
constants.OVN_PORT_BINDING_PROFILE: binding_profile}))
|
||||
@ -757,8 +760,9 @@ class TestValidateAndGetDataFromBindingProfile(base.BaseTestCase):
|
||||
}
|
||||
expect = binding_profile.copy()
|
||||
del(expect[constants.PORT_CAP_PARAM])
|
||||
self.assertDictEqual(
|
||||
expect,
|
||||
self.assertEqual(
|
||||
utils.BPInfo(expect, self.VNIC_FAKE_OTHER,
|
||||
[constants.PORT_CAP_SWITCHDEV]),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{portbindings.VNIC_TYPE: self.VNIC_FAKE_OTHER,
|
||||
constants.OVN_PORT_BINDING_PROFILE: binding_profile}))
|
||||
@ -775,7 +779,8 @@ class TestValidateAndGetDataFromBindingProfile(base.BaseTestCase):
|
||||
constants.PORT_CAP_PARAM: [constants.PORT_CAP_SWITCHDEV],
|
||||
}
|
||||
self.assertEqual(
|
||||
{},
|
||||
utils.BPInfo({}, self.VNIC_FAKE_OTHER,
|
||||
[constants.PORT_CAP_SWITCHDEV]),
|
||||
utils.validate_and_get_data_from_binding_profile(
|
||||
{portbindings.VNIC_TYPE: self.VNIC_FAKE_OTHER,
|
||||
constants.OVN_PORT_BINDING_PROFILE: binding_profile}))
|
||||
|
@ -71,6 +71,23 @@ class PortBindingDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
|
||||
# The PB register returned is the INACTIVE one.
|
||||
self.assertEqual(self.obj_fields[1]['host'], dup_pb[0].host)
|
||||
|
||||
def test_get_port_binding_by_vnic_type(self):
|
||||
self.update_obj_fields({'vnic_type': portbindings.VNIC_NORMAL},
|
||||
obj_fields=[self.obj_fields[0]])
|
||||
self.update_obj_fields({'vnic_type': portbindings.VNIC_DIRECT},
|
||||
obj_fields=[self.obj_fields[1],
|
||||
self.obj_fields[2]])
|
||||
for i in range(3):
|
||||
_obj = self._make_object(self.obj_fields[i])
|
||||
_obj.create()
|
||||
|
||||
for vnic_type, pb_num in [(portbindings.VNIC_NORMAL, 1),
|
||||
(portbindings.VNIC_DIRECT, 2),
|
||||
(portbindings.VNIC_MACVTAP, 0)]:
|
||||
pb = ports.PortBinding.get_port_binding_by_vnic_type(self.context,
|
||||
vnic_type)
|
||||
self.assertEqual(pb_num, len(pb))
|
||||
|
||||
|
||||
class DistributedPortBindingIfaceObjTestCase(
|
||||
obj_test_base.BaseObjectIfaceTestCase):
|
||||
|
@ -16,10 +16,12 @@
|
||||
from unittest import mock
|
||||
|
||||
from futurist import periodics
|
||||
from neutron_lib.api.definitions import portbindings
|
||||
from neutron_lib import constants as n_const
|
||||
from neutron_lib import context
|
||||
from neutron_lib.db import api as db_api
|
||||
from oslo_config import cfg
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from neutron.common.ovn import constants
|
||||
@ -27,6 +29,7 @@ from neutron.common.ovn import utils
|
||||
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf
|
||||
from neutron.db.models import ovn as ovn_models
|
||||
from neutron.db import ovn_revision_numbers_db
|
||||
from neutron.objects import ports as ports_obj
|
||||
from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import maintenance
|
||||
from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import ovn_db_sync
|
||||
from neutron.tests.unit import fake_resources as fakes
|
||||
@ -831,3 +834,23 @@ class TestDBInconsistenciesPeriodics(testlib_api.SqlTestCaseLight,
|
||||
self.assertEqual(
|
||||
2,
|
||||
nb_idl.delete_static_route.call_count)
|
||||
|
||||
@mock.patch.object(ports_obj.PortBinding, 'get_port_binding_by_vnic_type')
|
||||
def test_add_vnic_type_and_pb_capabilities_to_lsp(self, mock_get_pb):
|
||||
nb_idl = self.fake_ovn_client._nb_idl
|
||||
profile = {'capabilities': ['switchdev']}
|
||||
pb1 = mock.Mock(profile=jsonutils.dumps(profile), port_id='port1')
|
||||
pb2 = mock.Mock(profile=jsonutils.dumps(profile), port_id='port2')
|
||||
mock_get_pb.return_value = [pb1, pb2]
|
||||
|
||||
self.assertRaises(
|
||||
periodics.NeverAgain,
|
||||
self.periodic.add_vnic_type_and_pb_capabilities_to_lsp)
|
||||
external_ids = {
|
||||
constants.OVN_PORT_VNIC_TYPE_KEY: portbindings.VNIC_DIRECT,
|
||||
constants.OVN_PORT_BP_CAPABILITIES_KEY: 'switchdev'}
|
||||
expected_calls = [mock.call(lport_name='port1', if_exists=True,
|
||||
external_ids=external_ids),
|
||||
mock.call(lport_name='port2', if_exists=True,
|
||||
external_ids=external_ids)]
|
||||
nb_idl.set_lswitch_port.assert_has_calls(expected_calls)
|
||||
|
@ -16,6 +16,7 @@
|
||||
from unittest import mock
|
||||
|
||||
from neutron.common.ovn import constants
|
||||
from neutron.conf.plugins.ml2 import config as ml2_conf
|
||||
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf
|
||||
from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import ovn_client
|
||||
from neutron.tests import base
|
||||
@ -28,6 +29,7 @@ from neutron_lib import constants as const
|
||||
class TestOVNClientBase(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
ml2_conf.register_ml2_plugin_opts()
|
||||
ovn_conf.register_opts()
|
||||
super(TestOVNClientBase, self).setUp()
|
||||
self.nb_idl = mock.MagicMock()
|
||||
@ -133,6 +135,7 @@ class TestOVNClientDetermineBindHost(TestOVNClientBase):
|
||||
def test_vnic_remote_managed_unbound_port_no_binding_profile(self):
|
||||
port = {
|
||||
portbindings.VNIC_TYPE: portbindings.VNIC_REMOTE_MANAGED,
|
||||
constants.OVN_PORT_BINDING_PROFILE: {},
|
||||
}
|
||||
self.assertEqual(
|
||||
'',
|
||||
|
@ -1800,7 +1800,9 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
'ip_address': '10.0.0.55'},
|
||||
{'subnet_id': 'subnet-2',
|
||||
'ip_address': '10.0.1.55'},
|
||||
]}
|
||||
],
|
||||
portbindings.PROFILE: {},
|
||||
}
|
||||
subnet_ids = [
|
||||
ip['subnet_id']
|
||||
for ip in port.get('fixed_ips')
|
||||
@ -1826,6 +1828,7 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
{"subnet_id": "subnet-1", "ip_address": "10.0.0.55"},
|
||||
{"subnet_id": "subnet-2", "ip_address": "aef0::4"},
|
||||
],
|
||||
portbindings.PROFILE: {},
|
||||
}
|
||||
|
||||
subnet_ids = [ip["subnet_id"] for ip in port.get("fixed_ips")]
|
||||
@ -1910,6 +1913,7 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
'network_id': 'foo',
|
||||
'fixed_ips': [],
|
||||
portbindings.HOST_ID: 'fake-src',
|
||||
portbindings.PROFILE: {},
|
||||
}
|
||||
with mock.patch.object(
|
||||
self.mech_driver._ovn_client._sb_idl, 'is_col_present',
|
||||
@ -1942,7 +1946,9 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase):
|
||||
'ip_address': '10.0.0.55'},
|
||||
{'subnet_id': 'subnet-2',
|
||||
'ip_address': '10.0.1.55'},
|
||||
]}
|
||||
],
|
||||
portbindings.PROFILE: {},
|
||||
}
|
||||
subnet_ids = [
|
||||
ip['subnet_id']
|
||||
for ip in port.get('fixed_ips')
|
||||
@ -4292,7 +4298,9 @@ class TestOVNVVirtualPort(OVNMechanismDriverTestCase):
|
||||
'device_owner': device_owner,
|
||||
'network_id': self.net['id'],
|
||||
'fixed_ips': [{'subnet_id': self.subnet['id'],
|
||||
'ip_address': '10.0.0.55'}]}
|
||||
'ip_address': '10.0.0.55'}],
|
||||
portbindings.PROFILE: {},
|
||||
}
|
||||
port_info = self.mech_driver._ovn_client._get_port_options(port)
|
||||
self.assertEqual(ovn_const.LSP_TYPE_VIRTUAL, port_info.type)
|
||||
self.assertEqual(
|
||||
|
Loading…
x
Reference in New Issue
Block a user