Qos SR-IOV: Refactor extension delete to get mac and pci slot

When calling delete we need the pci slot details to reset the VF rate. The problem
is that when the VM is deleted libvirt return the VF to the hypervisor and eswitch
manager will mark the pci_slot as unassigned so can't know from the mac which pci slot (VF)
to reset. Also newer libvirt version reset the mac when deleteing VM, so than it is
not possible at all.
The solution is to keep pci slot details locally in the agent since upon removal event
you cannot get pci_slot from the neutron server as it is for create/update since port
is already removed from neutron.

This patch pairs the mac and pci_slot for a device (VF) so when calling the extension
port delete api we can have the pci_slot and reset the VF rate.

It is also add a mapping between mac to port_id so we can pass the port_id
when calling the extention port delete api.

Partially-Implements: blueprint ml2-sriov-qos-with-bwlimiting
Closes-Bug: #1492909
Change-Id: Icc3a9599c6d7a4de9c56b452dfab7909c8d0a576
This commit is contained in:
Moshe Levi 2015-08-18 08:48:24 +03:00
parent 4cbcb2eba4
commit 13901bdf69
8 changed files with 210 additions and 95 deletions

View File

@ -125,20 +125,25 @@ class EmbSwitch(object):
"""Get list of VF addresses."""
return self.pci_slot_map.keys()
def get_assigned_devices(self):
"""Get assigned Virtual Functions.
def get_assigned_devices_info(self):
"""Get assigned Virtual Functions mac and pci slot
information and populates vf_to_pci_slot mappings
@return: list of VF mac addresses
@return: list of VF pair (mac address, pci slot)
"""
vf_list = []
assigned_macs = []
for vf_index in self.pci_slot_map.values():
vf_to_pci_slot_mapping = {}
assigned_devices_info = []
for pci_slot, vf_index in self.pci_slot_map.items():
if not PciOsWrapper.is_assigned_vf(self.dev_name, vf_index):
continue
vf_list.append(vf_index)
if vf_list:
assigned_macs = self.pci_dev_wrapper.get_assigned_macs(vf_list)
return assigned_macs
vf_to_pci_slot_mapping[vf_index] = pci_slot
if vf_to_pci_slot_mapping:
vf_to_mac_mapping = self.pci_dev_wrapper.get_assigned_macs(
list(vf_to_pci_slot_mapping.keys()))
for vf_index, mac in vf_to_mac_mapping.items():
pci_slot = vf_to_pci_slot_mapping[vf_index]
assigned_devices_info.append((mac, pci_slot))
return assigned_devices_info
def get_device_state(self, pci_slot):
"""Get device state.
@ -219,8 +224,7 @@ class EmbSwitch(object):
if vf_index is not None:
if PciOsWrapper.is_assigned_vf(self.dev_name, vf_index):
macs = self.pci_dev_wrapper.get_assigned_macs([vf_index])
if macs:
mac = macs[0]
mac = macs.get(vf_index)
return mac
@ -247,12 +251,12 @@ class ESwitchManager(object):
return True
return False
def get_assigned_devices(self, phys_net=None):
def get_assigned_devices_info(self, phys_net=None):
"""Get all assigned devices.
Get all assigned devices belongs to given embedded switch
@param phys_net: physical network, if none get all assigned devices
@return: set of assigned VFs mac addresses
@return: set of assigned VFs (mac address, pci slot) pair
"""
if phys_net:
embedded_switch = self.emb_switches_map.get(phys_net, None)
@ -263,8 +267,8 @@ class ESwitchManager(object):
eswitch_objects = self.emb_switches_map.values()
assigned_devices = set()
for embedded_switch in eswitch_objects:
for device_mac in embedded_switch.get_assigned_devices():
assigned_devices.add(device_mac)
for device in embedded_switch.get_assigned_devices_info():
assigned_devices.add(device)
return assigned_devices
def get_device_state(self, device_mac, pci_slot):
@ -272,7 +276,7 @@ class ESwitchManager(object):
Get the device state (up/True or down/False)
@param device_mac: device mac
@param pci_slot: VF pci slot
@param pci_slot: VF PCI slot
@return: device state (True/False) None if failed
"""
embedded_switch = self._get_emb_eswitch(device_mac, pci_slot)
@ -355,16 +359,27 @@ class ESwitchManager(object):
embedded_switch = None
return embedded_switch
def get_pci_slot_by_mac(self, device_mac):
"""Get pci slot by mac.
def clear_max_rate(self, pci_slot):
"""Clear the max rate
Get pci slot by device mac
@param device_mac: device mac
Clear the max rate configuration from VF by setting it to 0
@param pci_slot: VF PCI slot
"""
result = None
for pci_slot, embedded_switch in self.pci_slot_map.items():
used_device_mac = embedded_switch.get_pci_device(pci_slot)
if used_device_mac == device_mac:
result = pci_slot
break
return result
#(Note): we don't use the self._get_emb_eswitch here, because when
#clearing the VF it may be not assigned. This happens when libvirt
#releases the VF back to the hypervisor on delete VM. Therefore we
#should just clear the VF max rate according to pci_slot no matter
#if VF is assigned or not.
embedded_switch = self.pci_slot_map.get(pci_slot)
if embedded_switch:
#(Note): check the pci_slot is not assigned to some
# other port before resetting the max rate.
if embedded_switch.get_pci_device(pci_slot) is None:
embedded_switch.set_device_max_rate(pci_slot, 0)
else:
LOG.warning(_LW("VF with PCI slot %(pci_slot)s is already "
"assigned; skipping reset maximum rate"),
{'pci_slot': pci_slot})
else:
LOG.error(_LE("PCI slot %(pci_slot)s has no mapping to Embedded "
"Switch; skipping"), {'pci_slot': pci_slot})

View File

@ -69,8 +69,7 @@ class QosSRIOVAgentDriver(qos.QosAgentDriver):
def _delete_bandwidth_limit(self, port):
pci_slot = port['profile'].get('pci_slot')
device = port['device']
self._set_vf_max_rate(device, pci_slot)
self.eswitch_mgr.clear_max_rate(pci_slot)
def _set_vf_max_rate(self, device, pci_slot, max_kbps=0):
if self.eswitch_mgr.device_exists(device, pci_slot):

View File

@ -50,7 +50,7 @@ class PciDeviceIPWrapper(ip_lib.IPWrapper):
"""Get assigned mac addresses for vf list.
@param vf_list: list of vf indexes
@return: list of assigned mac addresses
@return: dict mapping of vf to mac
"""
try:
out = self._as_root([], "link", ("show", self.dev_name))
@ -58,14 +58,16 @@ class PciDeviceIPWrapper(ip_lib.IPWrapper):
LOG.exception(_LE("Failed executing ip command"))
raise exc.IpCommandError(dev_name=self.dev_name,
reason=e)
vf_to_mac_mapping = {}
vf_lines = self._get_vf_link_show(vf_list, out)
vf_details_list = []
if vf_lines:
for vf_line in vf_lines:
vf_details = self._parse_vf_link_show(vf_line)
if vf_details:
vf_details_list.append(vf_details)
return [details.get("MAC") for details in vf_details_list]
vf_num = vf_details.get('vf')
vf_mac = vf_details.get("MAC")
vf_to_mac_mapping[vf_num] = vf_mac
return vf_to_mac_mapping
def get_vf_state(self, vf_index):
"""Get vf state {True/False}

View File

@ -64,8 +64,20 @@ class SriovNicSwitchRpcCallbacks(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
# Do not store port details, as if they're used for processing
# notifications there is no guarantee the notifications are
# processed in the same order as the relevant API requests.
self.agent.updated_devices.add(port['mac_address'])
LOG.debug("port_update RPC received for port: %s", port['id'])
mac = port['mac_address']
pci_slot = None
if port.get('binding:profile'):
pci_slot = port['binding:profile'].get('pci_slot')
if pci_slot:
self.agent.updated_devices.add((mac, pci_slot))
LOG.debug("port_update RPC received for port: %(id)s with MAC "
"%(mac)s and PCI slot %(pci_slot)s slot",
{'id': port['id'], 'mac': mac, 'pci_slot': pci_slot})
else:
LOG.debug("No PCI Slot for port %(id)s with MAC %(mac)s; "
"skipping", {'id': port['id'], 'mac': mac,
'pci_slot': pci_slot})
class SriovNicSwitchAgent(object):
@ -87,6 +99,7 @@ class SriovNicSwitchAgent(object):
# Stores port update notifications for processing in the main loop
self.updated_devices = set()
self.mac_to_port_id_mapping = {}
self.context = context.get_admin_context_without_session()
self.plugin_rpc = agent_rpc.PluginApi(topics.PLUGIN)
@ -128,7 +141,7 @@ class SriovNicSwitchAgent(object):
def _report_state(self):
try:
devices = len(self.eswitch_mgr.get_assigned_devices())
devices = len(self.eswitch_mgr.get_assigned_devices_info())
self.agent_state.get('configurations')['devices'] = devices
self.state_rpc.report_state(self.context,
self.agent_state)
@ -147,7 +160,7 @@ class SriovNicSwitchAgent(object):
self.eswitch_mgr.discover_devices(device_mappings, exclude_devices)
def scan_devices(self, registered_devices, updated_devices):
curr_devices = self.eswitch_mgr.get_assigned_devices()
curr_devices = self.eswitch_mgr.get_assigned_devices_info()
device_info = {}
device_info['current'] = curr_devices
device_info['added'] = curr_devices - registered_devices
@ -214,14 +227,15 @@ class SriovNicSwitchAgent(object):
else:
LOG.info(_LI("No device with MAC %s defined on agent."), device)
def treat_devices_added_updated(self, devices):
def treat_devices_added_updated(self, devices_info):
try:
macs_list = set([device_info[0] for device_info in devices_info])
devices_details_list = self.plugin_rpc.get_devices_details_list(
self.context, devices, self.agent_id)
self.context, macs_list, self.agent_id)
except Exception as e:
LOG.debug("Unable to get port details for devices "
"with MAC address %(devices)s: %(e)s",
{'devices': devices, 'e': e})
"with MAC addresses %(devices)s: %(e)s",
{'devices': macs_list, 'e': e})
# resync is needed
return True
@ -232,9 +246,11 @@ class SriovNicSwitchAgent(object):
if 'port_id' in device_details:
LOG.info(_LI("Port %(device)s updated. Details: %(details)s"),
{'device': device, 'details': device_details})
port_id = device_details['port_id']
self.mac_to_port_id_mapping[device] = port_id
profile = device_details['profile']
spoofcheck = device_details.get('port_security_enabled', True)
self.treat_device(device_details['device'],
self.treat_device(device,
profile.get('pci_slot'),
device_details['admin_state_up'],
spoofcheck)
@ -247,31 +263,41 @@ class SriovNicSwitchAgent(object):
def treat_devices_removed(self, devices):
resync = False
for device in devices:
LOG.info(_LI("Removing device with mac_address %s"), device)
mac, pci_slot = device
LOG.info(_LI("Removing device with MAC address %(mac)s and "
"PCI slot %(pci_slot)s"),
{'mac': mac, 'pci_slot': pci_slot})
try:
pci_slot = self.eswitch_mgr.get_pci_slot_by_mac(device)
if pci_slot:
port_id = self.mac_to_port_id_mapping.get(mac)
if port_id:
profile = {'pci_slot': pci_slot}
port = {'device': device, 'profile': profile}
port = {'port_id': port_id,
'device': mac,
'profile': profile}
self.ext_manager.delete_port(self.context, port)
del self.mac_to_port_id_mapping[mac]
else:
LOG.warning(_LW("Failed to find pci slot for device "
"%(device)s; skipping extension port "
"cleanup"), device)
LOG.warning(_LW("port_id to device with MAC "
"%s not found"), mac)
dev_details = self.plugin_rpc.update_device_down(self.context,
device,
mac,
self.agent_id,
cfg.CONF.host)
except Exception as e:
LOG.debug("Removing port failed for device %(device)s "
"due to %(exc)s", {'device': device, 'exc': e})
LOG.debug("Removing port failed for device with MAC address "
"%(mac)s and PCI slot %(pci_slot)s due to %(exc)s",
{'mac': mac, 'pci_slot': pci_slot, 'exc': e})
resync = True
continue
if dev_details['exists']:
LOG.info(_LI("Port %s updated."), device)
LOG.info(_LI("Port with MAC %(mac)s and PCI slot "
"%(pci_slot)s updated."),
{'mac': mac, 'pci_slot': pci_slot})
else:
LOG.debug("Device %s not defined on plugin", device)
LOG.debug("Device with MAC %(mac)s and PCI slot "
"%(pci_slot)s not defined on plugin",
{'mac': mac, 'pci_slot': pci_slot})
return resync
def daemon_loop(self):

View File

@ -37,7 +37,9 @@ class QosSRIOVAgentDriverTestCase(base.BaseTestCase):
self.qos_driver.initialize()
self.qos_driver.eswitch_mgr = mock.Mock()
self.qos_driver.eswitch_mgr.set_device_max_rate = mock.Mock()
self.qos_driver.eswitch_mgr.clear_max_rate = mock.Mock()
self.max_rate_mock = self.qos_driver.eswitch_mgr.set_device_max_rate
self.clear_max_rate_mock = self.qos_driver.eswitch_mgr.clear_max_rate
self.rule = self._create_bw_limit_rule_obj()
self.qos_policy = self._create_qos_policy_obj([self.rule])
self.port = self._create_fake_port()
@ -78,8 +80,7 @@ class QosSRIOVAgentDriverTestCase(base.BaseTestCase):
def test_delete_rules(self):
self.qos_driver.delete(self.port, self.qos_policy)
self.max_rate_mock.assert_called_once_with(
self.ASSIGNED_MAC, self.PCI_SLOT, 0)
self.clear_max_rate_mock.assert_called_once_with(self.PCI_SLOT)
def test__set_vf_max_rate_captures_sriov_failure(self):
self.max_rate_mock.side_effect = exceptions.SriovNicError()

View File

@ -79,12 +79,13 @@ class TestESwitchManagerApi(base.BaseTestCase):
self.eswitch_mgr = esm.ESwitchManager()
self.eswitch_mgr.discover_devices(device_mappings, None)
def test_get_assigned_devices(self):
def test_get_assigned_devices_info(self):
with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.EmbSwitch.get_assigned_devices",
return_value=[self.ASSIGNED_MAC]):
result = self.eswitch_mgr.get_assigned_devices()
self.assertEqual(set([self.ASSIGNED_MAC]), result)
"eswitch_manager.EmbSwitch.get_assigned_devices_info",
return_value=[(self.ASSIGNED_MAC, self.PCI_SLOT)]):
result = self.eswitch_mgr.get_assigned_devices_info()
self.assertIn(self.ASSIGNED_MAC, list(result)[0])
self.assertIn(self.PCI_SLOT, list(result)[0])
def test_get_device_status_true(self):
with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
@ -196,23 +197,28 @@ class TestESwitchManagerApi(base.BaseTestCase):
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
"PciDeviceIPWrapper.get_assigned_macs",
return_value=[ASSIGNED_MAC])
return_value={})
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.PciOsWrapper.is_assigned_vf",
return_value=True)
def test_get_pci_slot_by_existing_mac(self, *args):
pci_slot = self.eswitch_mgr.get_pci_slot_by_mac(self.ASSIGNED_MAC)
self.assertIsNotNone(pci_slot)
"eswitch_manager.EmbSwitch.set_device_max_rate")
def test_clear_max_rate_existing_pci_slot(self, max_rate_mock, *args):
self.eswitch_mgr.clear_max_rate(self.PCI_SLOT)
max_rate_mock.assert_called_once_with(self.PCI_SLOT, 0)
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
"PciDeviceIPWrapper.get_assigned_macs",
return_value=[ASSIGNED_MAC])
return_value={0: ASSIGNED_MAC})
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.PciOsWrapper.is_assigned_vf",
return_value=True)
def test_get_pci_slot_by_not_existing_mac(self, *args):
pci_slot = self.eswitch_mgr.get_pci_slot_by_mac(self.WRONG_MAC)
self.assertIsNone(pci_slot)
"eswitch_manager.EmbSwitch.set_device_max_rate")
def test_clear_max_rate_exist_and_assigned_pci(
self, max_rate_mock, *args):
self.eswitch_mgr.clear_max_rate(self.PCI_SLOT)
self.assertFalse(max_rate_mock.called)
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.EmbSwitch.set_device_max_rate")
def test_clear_max_rate_nonexisting_pci_slot(self, max_rate_mock):
self.eswitch_mgr.clear_max_rate(self.WRONG_PCI)
self.assertFalse(max_rate_mock.called)
class TestEmbSwitch(base.BaseTestCase):
@ -224,6 +230,13 @@ class TestEmbSwitch(base.BaseTestCase):
SCANNED_DEVICES = [('0000:06:00.1', 0),
('0000:06:00.2', 1),
('0000:06:00.3', 2)]
VF_TO_MAC_MAPPING = {0: '00:00:00:00:00:11',
1: '00:00:00:00:00:22',
2: '00:00:00:00:00:33'}
EXPECTED_MAC_TO_PCI = {
'00:00:00:00:00:11': '0000:06:00.1',
'00:00:00:00:00:22': '0000:06:00.2',
'00:00:00:00:00:33': '0000:06:00.3'}
def setUp(self):
super(TestEmbSwitch, self).setUp()
@ -234,21 +247,44 @@ class TestEmbSwitch(base.BaseTestCase):
self.emb_switch = esm.EmbSwitch(self.PHYS_NET, self.DEV_NAME,
exclude_devices)
def test_get_assigned_devices(self):
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.PciOsWrapper.scan_vf_devices",
return_value=[(PCI_SLOT, 0)])
def test_get_assigned_devices_info(self, *args):
emb_switch = esm.EmbSwitch(self.PHYS_NET, self.DEV_NAME, ())
with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
"PciDeviceIPWrapper.get_assigned_macs",
return_value=[self.ASSIGNED_MAC]),\
return_value={0: self.ASSIGNED_MAC}),\
mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.PciOsWrapper.is_assigned_vf",
return_value=True):
result = self.emb_switch.get_assigned_devices()
self.assertEqual([self.ASSIGNED_MAC], result)
result = emb_switch.get_assigned_devices_info()
self.assertIn(self.ASSIGNED_MAC, list(result)[0])
self.assertIn(self.PCI_SLOT, list(result)[0])
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.PciOsWrapper.scan_vf_devices",
return_value=SCANNED_DEVICES)
def test_get_assigned_devices_info_multiple_slots(self, *args):
emb_switch = esm.EmbSwitch(self.PHYS_NET, self.DEV_NAME, ())
with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
"PciDeviceIPWrapper.get_assigned_macs",
return_value=self.VF_TO_MAC_MAPPING),\
mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.PciOsWrapper.is_assigned_vf",
return_value=True):
devices_info = emb_switch.get_assigned_devices_info()
for device_info in devices_info:
mac = device_info[0]
pci_slot = device_info[1]
self.assertEqual(
self.EXPECTED_MAC_TO_PCI[mac], pci_slot)
def test_get_assigned_devices_empty(self):
with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.PciOsWrapper.is_assigned_vf",
return_value=False):
result = self.emb_switch.get_assigned_devices()
result = self.emb_switch.get_assigned_devices_info()
self.assertFalse(result)
def test_get_device_state_ok(self):
@ -341,7 +377,7 @@ class TestEmbSwitch(base.BaseTestCase):
def test_get_pci_device(self):
with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
"PciDeviceIPWrapper.get_assigned_macs",
return_value=[self.ASSIGNED_MAC]),\
return_value={0: self.ASSIGNED_MAC}),\
mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.PciOsWrapper.is_assigned_vf",
return_value=True):

View File

@ -53,7 +53,8 @@ class TestPciLib(base.BaseTestCase):
"_as_root") as mock_as_root:
mock_as_root.return_value = self.VF_LINK_SHOW
result = self.pci_wrapper.get_assigned_macs([self.VF_INDEX])
self.assertEqual([self.MAC_MAPPING[self.VF_INDEX]], result)
self.assertEqual(
{self.VF_INDEX: self.MAC_MAPPING[self.VF_INDEX]}, result)
def test_get_assigned_macs_fail(self):
with mock.patch.object(self.pci_wrapper,

View File

@ -16,12 +16,14 @@
import mock
from oslo_config import cfg
from oslo_utils import uuidutils
from neutron.plugins.ml2.drivers.mech_sriov.agent.common import config # noqa
from neutron.plugins.ml2.drivers.mech_sriov.agent import sriov_nic_agent
from neutron.tests import base
DEVICE_MAC = '11:22:33:44:55:66'
PCI_SLOT = "0000:06:00.1"
class TestSriovAgent(base.BaseTestCase):
@ -51,33 +53,30 @@ class TestSriovAgent(base.BaseTestCase):
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
"PciDeviceIPWrapper.get_assigned_macs",
return_value=[DEVICE_MAC])
return_value=[(DEVICE_MAC, PCI_SLOT)])
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.PciOsWrapper.is_assigned_vf",
return_value=True)
def test_treat_devices_removed_with_existed_device(self, *args):
agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0)
devices = [DEVICE_MAC]
devices = [(DEVICE_MAC, PCI_SLOT)]
with mock.patch.object(agent.plugin_rpc,
"update_device_down") as fn_udd:
fn_udd.return_value = {'device': DEVICE_MAC,
'exists': True}
with mock.patch.object(sriov_nic_agent.LOG,
'info') as log:
resync = agent.treat_devices_removed(devices)
self.assertEqual(2, log.call_count)
self.assertFalse(resync)
self.assertTrue(fn_udd.called)
resync = agent.treat_devices_removed(devices)
self.assertFalse(resync)
self.assertTrue(fn_udd.called)
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
"PciDeviceIPWrapper.get_assigned_macs",
return_value=[DEVICE_MAC])
return_value=[(DEVICE_MAC, PCI_SLOT)])
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.PciOsWrapper.is_assigned_vf",
return_value=True)
def test_treat_devices_removed_with_not_existed_device(self, *args):
agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0)
devices = [DEVICE_MAC]
devices = [(DEVICE_MAC, PCI_SLOT)]
with mock.patch.object(agent.plugin_rpc,
"update_device_down") as fn_udd:
fn_udd.return_value = {'device': DEVICE_MAC,
@ -91,13 +90,13 @@ class TestSriovAgent(base.BaseTestCase):
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
"PciDeviceIPWrapper.get_assigned_macs",
return_value=[DEVICE_MAC])
return_value=[(DEVICE_MAC, PCI_SLOT)])
@mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent."
"eswitch_manager.PciOsWrapper.is_assigned_vf",
return_value=True)
def test_treat_devices_removed_failed(self, *args):
agent = sriov_nic_agent.SriovNicSwitchAgent({}, {}, 0)
devices = [DEVICE_MAC]
devices = [(DEVICE_MAC, PCI_SLOT)]
with mock.patch.object(agent.plugin_rpc,
"update_device_down") as fn_udd:
fn_udd.side_effect = Exception()
@ -111,7 +110,8 @@ class TestSriovAgent(base.BaseTestCase):
def mock_scan_devices(self, expected, mock_current,
registered_devices, updated_devices):
self.agent.eswitch_mgr = mock.Mock()
self.agent.eswitch_mgr.get_assigned_devices.return_value = mock_current
self.agent.eswitch_mgr.get_assigned_devices_info.return_value = (
mock_current)
results = self.agent.scan_devices(registered_devices, updated_devices)
self.assertEqual(expected, results)
@ -238,3 +238,38 @@ class TestSriovAgent(base.BaseTestCase):
self.assertFalse(resync_needed)
self.assertFalse(agent.plugin_rpc.update_device_up.called)
class FakeAgent(object):
def __init__(self):
self.updated_devices = set()
class TestSriovNicSwitchRpcCallbacks(base.BaseTestCase):
def setUp(self):
super(TestSriovNicSwitchRpcCallbacks, self).setUp()
self.context = object()
self.agent = FakeAgent()
sg_agent = object()
self.sriov_rpc_callback = sriov_nic_agent.SriovNicSwitchRpcCallbacks(
self.context, self.agent, sg_agent)
def _create_fake_port(self):
return {'id': uuidutils.generate_uuid(),
'binding:profile': {'pci_slot': PCI_SLOT},
'mac_address': DEVICE_MAC}
def test_port_update_with_pci_slot(self):
port = self._create_fake_port()
kwargs = {'context': self.context, 'port': port}
self.sriov_rpc_callback.port_update(**kwargs)
self.assertEqual(set([(DEVICE_MAC, PCI_SLOT)]),
self.agent.updated_devices)
def test_port_update_without_pci_slot(self):
port = self._create_fake_port()
port['binding:profile'] = None
kwargs = {'context': self.context, 'port': port}
self.sriov_rpc_callback.port_update(**kwargs)
self.assertEqual(set(), self.agent.updated_devices)