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:
parent
4cbcb2eba4
commit
13901bdf69
|
@ -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})
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue