Merge "Add Smart NIC representor port to integration bridge"

This commit is contained in:
Zuul 2019-05-31 12:05:36 +00:00 committed by Gerrit Code Review
commit 3e6376f428
16 changed files with 414 additions and 29 deletions

View File

@ -62,6 +62,7 @@ openstacksdk==0.11.2
os-client-config==1.28.0
os-ken==0.3.0
os-service-types==1.2.0
os-vif==1.15.1
os-xenapi==0.3.1
osc-lib==1.8.0
oslo.cache==1.26.0

View File

@ -113,6 +113,7 @@ class PluginApi(object):
1.5 - Support update_device_list and
get_devices_details_list_and_failed_devices
1.6 - Support get_network_details
1.7 - Support get_ports_by_vnic_type_and_host
'''
def __init__(self, topic):
@ -192,6 +193,11 @@ class PluginApi(object):
return cctxt.call(context, 'tunnel_sync', tunnel_ip=tunnel_ip,
tunnel_type=tunnel_type, host=host)
def get_ports_by_vnic_type_and_host(self, context, vnic_type, host):
cctxt = self.client.prepare(version='1.7')
return cctxt.call(context, 'get_ports_by_vnic_type_and_host',
vnic_type=vnic_type, host=host)
def create_cache_for_l2_agent():
"""Create a push-notifications cache for L2 agent related resources."""
@ -336,6 +342,7 @@ class CacheBackedPluginApi(PluginApi):
dialect=netaddr.mac_unix_expanded))
entry = {
'device': device,
'device_id': port_obj.device_id,
'network_id': port_obj.network_id,
'port_id': port_obj.id,
'mac_address': mac_addr,
@ -355,6 +362,8 @@ class CacheBackedPluginApi(PluginApi):
'qos_policy_id': port_obj.qos_policy_id,
'network_qos_policy_id': net_qos_policy_id,
'profile': binding.profile,
'vif_type': binding.vif_type,
'vnic_type': binding.vnic_type,
'security_groups': list(port_obj.security_group_ids)
}
LOG.debug("Returning: %s", entry)

View File

@ -162,7 +162,9 @@ agent_opts = [
"outgoing IP packet carrying GRE/VXLAN tunnel.")),
cfg.StrOpt('agent_type', default=n_const.AGENT_TYPE_OVS,
deprecated_for_removal=True,
help=_("Selects the Agent Type reported"))
help=_("Selects the Agent Type reported.")),
cfg.BoolOpt('baremetal_smartnic', default=False,
help=_("Enable the agent to process Smart NIC ports.")),
]

View File

@ -531,3 +531,13 @@ class Port(base.NeutronDbObject):
ml2_models.PortBinding.vif_type == binding_type,
ml2_models.PortBinding.host == host)
return [cls._load_object(context, db_obj) for db_obj in query.all()]
@classmethod
def get_ports_by_vnic_type_and_host(
cls, context, vnic_type, host):
query = context.session.query(models_v2.Port).join(
ml2_models.PortBinding)
query = query.filter(
ml2_models.PortBinding.vnic_type == vnic_type,
ml2_models.PortBinding.host == host)
return [cls._load_object(context, db_obj) for db_obj in query.all()]

View File

@ -105,6 +105,11 @@ class AgentMechanismDriverBase(api.MechanismDriver):
for agent in agents:
LOG.debug("Checking agent: %s", agent)
if agent['alive']:
if (vnic_type == portbindings.VNIC_SMARTNIC and not
agent['configurations'].get('baremetal_smartnic')):
LOG.debug('Agent on host %s can not bind SmartNIC '
'port %s', agent['host'], context.current['id'])
continue
for segment in context.segments_to_bind:
if self.try_to_bind_segment_for_agent(context, segment,
agent):

View File

@ -34,6 +34,10 @@ from neutron_lib import context
from neutron_lib.placement import utils as place_utils
from neutron_lib.plugins import utils as plugin_utils
from neutron_lib.utils import helpers
import os_vif
from os_vif.objects import instance_info as vif_instance_object
from os_vif.objects import network as vif_network_object
from os_vif.objects import vif as vif_obj
from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging
@ -128,7 +132,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
# 1.3 Added param devices_to_update to security_groups_provider_updated
# 1.4 Added support for network_update
# 1.5 Added binding_activate and binding_deactivate
target = oslo_messaging.Target(version='1.5')
# 1.7 Add support for smartnic ports
target = oslo_messaging.Target(version='1.7')
def __init__(self, bridge_classes, ext_manager, conf=None):
'''Constructor.
@ -182,6 +187,8 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
self.deactivated_bindings = set()
# Stores the port IDs whose binding has been activated
self.activated_bindings = set()
# Stores smartnic ports update/remove
self.updated_smartnic_ports = list()
self.network_ports = collections.defaultdict(set)
# keeps association between ports and ofports to detect ofport change
@ -303,7 +310,9 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
'ovs_capabilities': self.ovs.capabilities,
'vhostuser_socket_dir':
ovs_conf.vhostuser_socket_dir,
portbindings.OVS_HYBRID_PLUG: hybrid_plug},
portbindings.OVS_HYBRID_PLUG: hybrid_plug,
'baremetal_smartnic':
self.conf.AGENT.baremetal_smartnic},
'resource_versions': resources.LOCAL_RESOURCE_VERSIONS,
'agent_type': agent_conf.agent_type,
'start_flag': True}
@ -320,6 +329,9 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
self.catch_sigterm = False
self.catch_sighup = False
if self.conf.AGENT.baremetal_smartnic:
os_vif.initialize()
# The initialization is complete; we can start receiving messages
self.connection.consume_in_threads()
@ -474,6 +486,79 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
# are processed in the same order as the relevant API requests
self.updated_ports.add(port['id'])
if not self.conf.AGENT.baremetal_smartnic:
return
# In case of smart-nic port, add smart-nic representor port to
# the integration bridge.
port_data = (self.plugin_rpc.remote_resource_cache
.get_resource_by_id(resources.PORT, port['id']))
if not port_data:
LOG.warning('Failed to get port details, port id: %s', port['id'])
return
for port_binding in port_data.get('bindings', []):
if port_binding['vnic_type'] == portbindings.VNIC_SMARTNIC:
if port_binding['host'] == self.conf.host:
self._add_port_to_updated_smartnic_ports(port_data,
port_binding)
else:
# The port doesn't belong to this Smart NIC,
# the reason for this could be multi Smart NIC
# setup.
LOG.info("Smart NIC port %(port_id)s does not belong "
"to host %(host)s",
{'port_id': port['id'],
'host': self.conf.host})
def treat_smartnic_port(self, smartnic_port_data):
mac = smartnic_port_data['mac']
vm_uuid = smartnic_port_data['vm_uuid']
rep_port = smartnic_port_data['iface_name']
iface_id = smartnic_port_data['iface_id']
vif_type = smartnic_port_data['vif_type']
instance_info = vif_instance_object.InstanceInfo(uuid=vm_uuid)
vif = self._get_vif_object(iface_id, rep_port, mac)
try:
if vif_type == portbindings.VIF_TYPE_OVS:
os_vif.plug(vif, instance_info)
elif vif_type == portbindings.VIF_TYPE_UNBOUND:
os_vif.unplug(vif, instance_info)
else:
LOG.error("Unexpected vif_type:%(vif_type)s for "
"%(vnic_type)s port:%(port_id)s",
{'vnic_type': portbindings.VNIC_SMARTNIC,
'vif_type': vif_type,
'port_id': iface_id})
except Exception as e:
LOG.error("Failed to treat %(vnic_type)s port:%(port_id)s , "
"error:%(error)s",
{'vnic_type': portbindings.VNIC_SMARTNIC,
'port_id': iface_id,
'error': e})
def _get_vif_object(self, iface_id, rep_port, mac):
network = vif_network_object.Network(
bridge=self.conf.OVS.integration_bridge)
port_profile = vif_obj.VIFPortProfileOpenVSwitch(
interface_id=iface_id, create_port=True)
return vif_obj.VIFOpenVSwitch(
vif_name=rep_port, plugin='ovs', port_profile=port_profile,
network=network, address=str(mac))
def _add_port_to_updated_smartnic_ports(self, port_data, port_binding):
local_link = port_binding['profile']['local_link_information']
if local_link:
iface_name = local_link[0]['port_id']
self.updated_smartnic_ports.append({
'mac': port_data['mac_address'],
'vm_uuid': port_data['device_id'],
'iface_name': iface_name,
'iface_id': port_data['id'],
'vif_type': port_binding['vif_type']})
def port_delete(self, context, **kwargs):
port_id = kwargs.get('port_id')
self.deleted_ports.add(port_id)
@ -536,6 +621,17 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
# more secure
self.sg_agent.remove_devices_filter(deleted_ports)
def process_smartnic_ports(self):
smartnic_ports = self.plugin_rpc.get_ports_by_vnic_type_and_host(
self.context, portbindings.VNIC_SMARTNIC, self.conf.host)
ports = self.int_br.get_vif_port_set()
for smartnic_port in smartnic_ports:
if smartnic_port['id'] not in ports:
self._add_port_to_updated_smartnic_ports(
smartnic_port,
{'profile': smartnic_port['binding:profile'],
'vif_type': smartnic_port['binding:vif_type']})
def process_deactivated_bindings(self, port_info):
# don't try to deactivate bindings for removed ports since they are
# already gone
@ -1972,6 +2068,7 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
self.deleted_ports or
self.deactivated_bindings or
self.activated_bindings or
self.updated_smartnic_ports or
self.sg_agent.firewall_refresh_needed())
def _port_info_has_changes(self, port_info):
@ -2249,6 +2346,16 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin,
"starting polling. Elapsed:%(elapsed).3f",
{'iter_num': self.iter_num,
'elapsed': time.time() - start})
if self.conf.AGENT.baremetal_smartnic:
if sync:
self.process_smartnic_ports()
updated_smartnic_ports_copy = (
self.updated_smartnic_ports)
self.updated_smartnic_ports = list()
for port_data in updated_smartnic_ports_copy:
self.treat_smartnic_port(port_data)
# Save updated ports dict to perform rollback in
# case resync would be needed, and then clear
# self.updated_ports. As the greenthread should not yield

View File

@ -77,7 +77,9 @@ class OpenvswitchMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
# SimpleAgentMechanismDriverBase. By that e blacklisting and validation
# of the vnic_types would be available for all mechanism drivers.
self.supported_vnic_types = self.blacklist_supported_vnic_types(
vnic_types=[portbindings.VNIC_NORMAL, portbindings.VNIC_DIRECT],
vnic_types=[portbindings.VNIC_NORMAL,
portbindings.VNIC_DIRECT,
portbindings.VNIC_SMARTNIC],
blacklist=cfg.CONF.OVS_DRIVER.vnic_type_blacklist
)
LOG.info("%s's supported_vnic_types: %s",

View File

@ -2517,3 +2517,11 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
db.clear_binding_levels(context,
port_id=port_id,
host=host)
@db_api.retry_if_session_inactive()
def get_ports_by_vnic_type_and_host(self, context, **kwargs):
host = kwargs['host']
vnic_type = kwargs['vnic_type']
ports = ports_obj.Port.get_ports_by_vnic_type_and_host(
context, vnic_type, host)
return [self._make_port_dict(port.db_obj) for port in ports]

View File

@ -52,7 +52,8 @@ class RpcCallbacks(type_tunnel.TunnelRpcCallbackMixin):
# 1.5 Support update_device_list and
# get_devices_details_list_and_failed_devices
# 1.6 Support get_network_details
target = oslo_messaging.Target(version='1.6')
# 1.7 Support get_ports_by_vnic_type_and_host
target = oslo_messaging.Target(version='1.7')
def __init__(self, notifier, type_manager):
self.setup_tunnel_callback_mixin(notifier, type_manager)
@ -399,6 +400,11 @@ class RpcCallbacks(type_tunnel.TunnelRpcCallbackMixin):
'devices_down': devices_down,
'failed_devices_down': failed_devices_down}
def get_ports_by_vnic_type_and_host(self, rpc_context, vnic_type, host):
plugin = directory.get_plugin()
return plugin.get_ports_by_vnic_type_and_host(
rpc_context, vnic_type=vnic_type, host=host)
class AgentNotifierApi(dvr_rpc.DVRAgentRpcApiMixin,
sg_rpc.SecurityGroupAgentRpcApiMixin,

View File

@ -44,6 +44,11 @@ class AgentRPCPluginApi(base.BaseTestCase):
func_obj = getattr(agent, method)
if method == 'tunnel_sync':
actual_val = func_obj(ctxt, 'fake_tunnel_ip')
elif method == 'get_ports_by_vnic_type_and_host':
actual_val = func_obj(ctxt, 'fake_vnic_type', 'fake_host')
mock_call.assert_called_once_with(
ctxt, 'get_ports_by_vnic_type_and_host',
host='fake_host', vnic_type='fake_vnic_type')
else:
actual_val = func_obj(ctxt, 'fake_device', 'fake_agent_id')
self.assertEqual(actual_val, expect_val)
@ -63,6 +68,9 @@ class AgentRPCPluginApi(base.BaseTestCase):
def test_tunnel_sync(self):
self._test_rpc_call('tunnel_sync')
def test_get_ports_by_vnic_type_and_host(self):
self._test_rpc_call('get_ports_by_vnic_type_and_host')
class AgentPluginReportState(base.BaseTestCase):
def test_plugin_report_state_use_call(self):
@ -191,6 +199,7 @@ class TestCacheBackedPluginApi(base.BaseTestCase):
segments=[self._segment])
self._port = ports.Port(
id=self._port_id, network_id=self._network_id,
device_id='vm_uuid',
mac_address=netaddr.EUI('fa:16:3e:ec:c7:d9'), admin_state_up=True,
security_group_ids=set([uuidutils.generate_uuid()]),
fixed_ips=[], allowed_address_pairs=[],
@ -198,7 +207,9 @@ class TestCacheBackedPluginApi(base.BaseTestCase):
bindings=[ports.PortBinding(port_id=self._port_id,
host='host1',
status=constants.ACTIVE,
profile={})],
profile={},
vif_type='vif_type',
vnic_type='vnic_type')],
binding_levels=[ports.PortBindingLevel(port_id=self._port_id,
host='host1',
level=0,

View File

@ -478,3 +478,20 @@ class PortDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
ports.Port.get_ports_ids_by_security_groups(
self.context, security_group_ids=(sg_id, ),
excluded_device_owners=filter_owner)))
def test_get_ports_by_vnic_type_and_host(self):
port1 = self._create_test_port()
ports.PortBinding(
self.context,
host='host1', port_id=port1.id, status='ACTIVE',
vnic_type='vnic_type1', vif_type='vif_type1').create()
port2 = self._create_test_port()
ports.PortBinding(
self.context,
host='host1', port_id=port2.id, status='ACTIVE',
vnic_type='vnic_type2', vif_type='vif_type1').create()
self.assertEqual(1, len(
ports.Port.get_ports_by_vnic_type_and_host(
self.context, 'vnic_type1', 'host1')))

View File

@ -16,10 +16,14 @@ import sys
import time
import mock
import netaddr
from neutron_lib.agent import constants as agent_consts
from neutron_lib.api.definitions import portbindings
from neutron_lib.api.definitions import provider_net
from neutron_lib import constants as n_const
from neutron_lib import rpc as n_rpc
import os_vif
from os_vif.objects import instance_info as vif_instance_object
from oslo_config import cfg
from oslo_log import log
import oslo_messaging
@ -31,6 +35,8 @@ from neutron.agent.common import ovs_lib
from neutron.agent.common import polling
from neutron.agent.common import utils
from neutron.agent.linux import ip_lib
from neutron.objects.ports import Port
from neutron.objects.ports import PortBinding
from neutron.plugins.ml2.drivers.l2pop import rpc as l2pop_rpc
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants
from neutron.plugins.ml2.drivers.openvswitch.agent import ovs_neutron_agent \
@ -967,7 +973,10 @@ class TestOvsNeutronAgent(object):
'failed_devices_up': [],
'failed_devices_down': []}):
with mock.patch.object(self.agent, 'port_unbound') as port_unbound:
self.assertFalse(self.agent.treat_devices_removed([{}]))
with mock.patch.object(self.agent.int_br,
'get_vif_port_by_id',
return_value=None):
self.assertFalse(self.agent.treat_devices_removed([{}]))
self.assertTrue(port_unbound.called)
def test_treat_devices_removed_unbinds_port(self):
@ -985,9 +994,14 @@ class TestOvsNeutronAgent(object):
'failed_devices_up': [],
'failed_devices_down': [
dev_mock]}):
failed_devices = {'added': set(), 'removed': set()}
failed_devices['removed'] = self.agent.treat_devices_removed([{}])
self.assertEqual(set([dev_mock]), failed_devices.get('removed'))
with mock.patch.object(self.agent.int_br,
'get_vif_port_by_id',
return_value=None):
failed_devices = {'added': set(), 'removed': set()}
failed_devices['removed'] = \
self.agent.treat_devices_removed([{}])
self.assertEqual(set([dev_mock]),
failed_devices.get('removed'))
def test_treat_devices_removed_ext_delete_port(self):
port_id = 'fake-id'
@ -999,10 +1013,12 @@ class TestOvsNeutronAgent(object):
'failed_devices_up': [],
'failed_devices_down': []})
m_unbound = mock.patch.object(self.agent, 'port_unbound')
with m_delete as delete, m_rpc, m_unbound:
self.agent.treat_devices_removed([port_id])
delete.assert_called_with(mock.ANY, {'port_id': port_id})
with mock.patch.object(self.agent.int_br,
'get_vif_port_by_id',
return_value=None):
self.agent.treat_devices_removed([port_id])
delete.assert_called_with(mock.ANY, {'port_id': port_id})
def test_treat_vif_port_shut_down_port(self):
details = mock.MagicMock()
@ -1176,15 +1192,54 @@ class TestOvsNeutronAgent(object):
self.assertTrue(self.agent.fullsync)
def test_port_update(self):
port = {"id": TEST_PORT_ID1,
"network_id": TEST_NETWORK_ID1,
"admin_state_up": False}
self.agent.port_update("unused_context",
port=port,
network_type="vlan",
segmentation_id="1",
physical_network="physnet")
self.assertEqual(set([TEST_PORT_ID1]), self.agent.updated_ports)
port_arg = {"id": TEST_PORT_ID1}
with mock.patch.object(self.agent.plugin_rpc.remote_resource_cache,
"get_resource_by_id") as mocked_resource:
port = Port()
port['mac_address'] = netaddr.EUI(FAKE_MAC)
port['device_id'] = '0'
port_bind = PortBinding()
port_bind['host'] = 'host'
port_bind['vnic_type'] = 'normal'
port.bindings = [port_bind]
mocked_resource.return_value = port
self.agent.port_update("unused_context",
port=port_arg,
network_type="vlan",
segmentation_id="1",
physical_network="physnet")
self.assertEqual(set([TEST_PORT_ID1]), self.agent.updated_ports)
self.assertEqual([], self.agent.updated_smartnic_ports)
def test_port_update_smartnic(self):
cfg.CONF.set_default('baremetal_smartnic', True, group='AGENT')
port_arg = {"id": TEST_PORT_ID1}
with mock.patch.object(self.agent.plugin_rpc.remote_resource_cache,
"get_resource_by_id") as mocked_resource:
port = Port()
port['id'] = 'd850ed99-5f46-47bc-8c06-86d9d519c46a'
port['mac_address'] = netaddr.EUI(FAKE_MAC)
port['device_id'] = '0'
port_bind = PortBinding()
port_bind['host'] = 'host'
port_bind['vnic_type'] = portbindings.VNIC_SMARTNIC
port_bind['vif_type'] = 'ovs'
port_bind['profile'] = {
'local_link_information': [{'port_id': 'rep_port'}]}
port.bindings = [port_bind]
mocked_resource.return_value = port
self.agent.port_update("unused_context",
port=port_arg)
expected_smartnic_data = {
'mac': port['mac_address'],
'vm_uuid': port['device_id'],
'iface_name': 'rep_port',
'iface_id': port['id'],
'vif_type': port_bind['vif_type']
}
self.assertEqual({TEST_PORT_ID1}, self.agent.updated_ports)
self.assertEqual([expected_smartnic_data],
self.agent.updated_smartnic_ports)
def test_port_delete_after_update(self):
"""Make sure a port is not marked for delete and update."""
@ -2421,6 +2476,133 @@ class TestOvsNeutronAgent(object):
self.agent._update_network_segmentation_id(network)
mock_update_segid.assert_not_called()
def _test_treat_smartnic_port(self, vif_type):
vm_uuid = "407a79e0-e0be-4b7d-92a6-513b2161011b"
iface_id = "407a79e0-e0be-4b7d-92a6-513b2161011c"
rep_port = 'rep0-0'
mac = FAKE_MAC
smartnic_data = {
'mac': mac,
'vm_uuid': vm_uuid,
'iface_name': rep_port,
'iface_id': iface_id,
'vif_type': vif_type}
cfg.CONF.set_default('baremetal_smartnic', True, group='AGENT')
agent = self._make_agent()
instance_info = vif_instance_object.InstanceInfo(uuid=vm_uuid)
vif = agent._get_vif_object(iface_id, rep_port, mac)
with mock.patch.object(os_vif, 'plug') as plug_mock, \
mock.patch.object(os_vif, 'unplug') as unplug_mock, \
mock.patch('os_vif.objects.instance_info.InstanceInfo',
return_value=instance_info), \
mock.patch.object(agent, '_get_vif_object',
return_value=vif):
agent.treat_smartnic_port(smartnic_data)
if vif_type == 'ovs':
plug_mock.assert_called_once_with(vif, instance_info)
else:
unplug_mock.assert_called_once_with(vif, instance_info)
def test_treat_smartnic_port_add(self):
self._test_treat_smartnic_port('ovs')
def test_treat_smartnic_port_remove(self):
self._test_treat_smartnic_port('unbound')
def test_process_smartnic_ports(self):
port_id_int_br = "407a79e0-e0be-4b7d-92a6-513b2161011a"
vm_uuid = "407a79e0-e0be-4b7d-92a6-513b2161011b"
iface_id = "407a79e0-e0be-4b7d-92a6-513b2161011c"
rep_port = 'rep0-0'
mac = FAKE_MAC
vif_type = "ovs"
EXISTING_PORT = {'id': port_id_int_br}
PORT_TO_PROCESS = {
'binding:profile': {'local_link_information': [
{'hostname': 'host1', 'port_id': rep_port}]},
'mac_address': FAKE_MAC,
'device_id': vm_uuid,
'id': iface_id,
'binding:vif_type': vif_type
}
with mock.patch.object(self.agent.int_br,
'get_vif_port_set',
return_value={port_id_int_br}),\
mock.patch.object(self.agent.plugin_rpc,
"get_ports_by_vnic_type_and_host",
return_value=[EXISTING_PORT,
PORT_TO_PROCESS]):
smartnic_data = {
'mac': mac,
'vm_uuid': vm_uuid,
'iface_name': rep_port,
'iface_id': iface_id,
'vif_type': vif_type}
self.agent.process_smartnic_ports()
self.assertEqual([smartnic_data],
self.agent.updated_smartnic_ports)
def test_add_port_to_updated_smartnic_ports_port_as_dict(self):
vm_uuid = "407a79e0-e0be-4b7d-92a6-513b2161011b"
iface_id = "407a79e0-e0be-4b7d-92a6-513b2161011c"
rep_port = 'rep0-0'
mac = FAKE_MAC
vif_type = "ovs"
PORT_TO_PROCESS = {
'binding:profile': {'local_link_information': [
{'hostname': 'host1', 'port_id': rep_port}]},
'mac_address': FAKE_MAC,
'device_id': vm_uuid,
'id': iface_id,
'binding:vif_type': vif_type
}
self.agent._add_port_to_updated_smartnic_ports(
PORT_TO_PROCESS,
{'profile': PORT_TO_PROCESS['binding:profile'],
'vif_type': PORT_TO_PROCESS['binding:vif_type']})
smartnic_data = {
'mac': mac,
'vm_uuid': vm_uuid,
'iface_name': rep_port,
'iface_id': iface_id,
'vif_type': vif_type}
self.assertEqual([smartnic_data],
self.agent.updated_smartnic_ports)
def test_add_port_to_updated_smartnic_ports_port_as_object(self):
vm_uuid = "407a79e0-e0be-4b7d-92a6-513b2161011b"
iface_id = "407a79e0-e0be-4b7d-92a6-513b2161011c"
rep_port = 'rep0-0'
mac = FAKE_MAC
vif_type = "ovs"
port = Port()
port['id'] = iface_id
port['mac_address'] = netaddr.EUI(mac)
port['device_id'] = vm_uuid
port_bind = PortBinding()
port_bind['profile'] = {'local_link_information': [
{'hostname': 'host1', 'port_id': rep_port}]}
port_bind['vif_type'] = vif_type
port_bind['host'] = 'host'
port_bind['vnic_type'] = portbindings.VNIC_SMARTNIC
port.bindings = [port_bind]
self.agent._add_port_to_updated_smartnic_ports(port, port_bind)
smartnic_data = {
'mac': mac,
'vm_uuid': vm_uuid,
'iface_name': rep_port,
'iface_id': iface_id,
'vif_type': vif_type}
self.assertEqual([smartnic_data],
self.agent.updated_smartnic_ports)
class TestOvsNeutronAgentOSKen(TestOvsNeutronAgent,
ovs_test_base.OVSOSKenTestBase):
@ -3124,7 +3306,10 @@ class TestOvsDvrNeutronAgent(object):
mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),\
mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),\
mock.patch.dict(self.agent.dvr_agent.phys_brs,
{self._physical_network: phys_br}):
{self._physical_network: phys_br}),\
mock.patch.object(self.agent.int_br,
'get_vif_port_by_id',
return_value=None):
failed_devices = {'added': set(), 'removed': set()}
failed_devices['removed'] = self.agent.treat_devices_removed(
[self._port.vif_id])
@ -3342,7 +3527,9 @@ class TestOvsDvrNeutronAgent(object):
mock.patch.object(self.agent, 'int_br', new=int_br),\
mock.patch.object(self.agent, 'tun_br', new=tun_br),\
mock.patch.object(self.agent.dvr_agent, 'int_br', new=int_br),\
mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br):
mock.patch.object(self.agent.dvr_agent, 'tun_br', new=tun_br),\
mock.patch.object(self.agent.int_br, 'get_vif_port_by_id',
return_value=None):
failed_devices = {'added': set(), 'removed': set()}
failed_devices['removed'] = self.agent.treat_devices_removed(
[self._port.vif_id])

View File

@ -329,19 +329,22 @@ class OpenvswitchMechanismSRIOVTestCase(OpenvswitchMechanismBaseTestCase):
class OpenvswitchMechVnicTypesTestCase(OpenvswitchMechanismBaseTestCase):
supported_vnics = [portbindings.VNIC_NORMAL,
portbindings.VNIC_DIRECT,
portbindings.VNIC_SMARTNIC]
def setUp(self):
self.blacklist_cfg = {
'OVS_DRIVER': {
'vnic_type_blacklist': []
}
}
self.default_supported_vnics = [portbindings.VNIC_NORMAL,
portbindings.VNIC_DIRECT]
self.default_supported_vnics = self.supported_vnics
super(OpenvswitchMechVnicTypesTestCase, self).setUp()
def test_default_vnic_types(self):
self.assertEqual([portbindings.VNIC_NORMAL,
portbindings.VNIC_DIRECT],
self.assertEqual(self.default_supported_vnics,
self.driver.supported_vnic_types)
def test_vnic_type_blacklist_valid_item(self):
@ -375,7 +378,7 @@ class OpenvswitchMechVnicTypesTestCase(OpenvswitchMechanismBaseTestCase):
def test_vnic_type_blacklist_all_items(self):
self.blacklist_cfg['OVS_DRIVER']['vnic_type_blacklist'] = \
[portbindings.VNIC_NORMAL, portbindings.VNIC_DIRECT]
self.supported_vnics
fake_conf = cfg.CONF
fake_conf_fixture = base.MechDriverConfFixture(
fake_conf, self.blacklist_cfg,

View File

@ -494,3 +494,12 @@ class RpcApiTestCase(base.BaseTestCase):
devices=['fake_device1', 'fake_device2'],
agent_id='fake_agent_id', host='fake_host',
version='1.5')
def test_get_ports_by_vnic_type_and_host(self):
rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
self._test_rpc_api(rpcapi, None,
'get_ports_by_vnic_type_and_host',
rpc_method='call',
vnic_type='fake_device1',
host='fake_host',
version='1.7')

View File

@ -0,0 +1,7 @@
---
prelude: >
Add Support for Smart NIC in ML2/OVS mechanism driver.
features:
- |
Add Support for Smart NIC in ML2/OVS mechanism driver, by extending the Neutron OVS mechanism
driver and Neutron OVS Agent to bind the Neutron port for the baremetal host with Smart NIC.

View File

@ -53,3 +53,4 @@ weakrefmethod>=1.0.2;python_version=='2.7' # PSF
python-novaclient>=9.1.0 # Apache-2.0
python-designateclient>=2.7.0 # Apache-2.0
os-xenapi>=0.3.1 # Apache-2.0
os-vif>=1.15.1 # Apache-2.0