From: Moshe Levi Date: Tue, 18 Aug 2015 05:48:24 +0000 (+0300) Subject: Qos SR-IOV: Refactor extension delete to get mac and pci slot X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=13901bdf6941d17069073f489798faaa86151fae;p=openstack-build%2Fneutron-build.git 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 --- diff --git a/neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py b/neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py index 12168883e..f5f66c9e9 100644 --- a/neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py +++ b/neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py @@ -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}) diff --git a/neutron/plugins/ml2/drivers/mech_sriov/agent/extension_drivers/qos_driver.py b/neutron/plugins/ml2/drivers/mech_sriov/agent/extension_drivers/qos_driver.py index 8c30817a1..4822360a7 100755 --- a/neutron/plugins/ml2/drivers/mech_sriov/agent/extension_drivers/qos_driver.py +++ b/neutron/plugins/ml2/drivers/mech_sriov/agent/extension_drivers/qos_driver.py @@ -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): diff --git a/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py b/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py index 8f984e0aa..f57be57bb 100644 --- a/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py +++ b/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py @@ -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} diff --git a/neutron/plugins/ml2/drivers/mech_sriov/agent/sriov_nic_agent.py b/neutron/plugins/ml2/drivers/mech_sriov/agent/sriov_nic_agent.py index 13210aa51..3bd141a95 100644 --- a/neutron/plugins/ml2/drivers/mech_sriov/agent/sriov_nic_agent.py +++ b/neutron/plugins/ml2/drivers/mech_sriov/agent/sriov_nic_agent.py @@ -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): diff --git a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/extension_drivers/test_qos_driver.py b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/extension_drivers/test_qos_driver.py index 7ccb74507..1541a299f 100755 --- a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/extension_drivers/test_qos_driver.py +++ b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/extension_drivers/test_qos_driver.py @@ -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() diff --git a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py index b3a7d958a..248426e9d 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py +++ b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py @@ -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 = 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): - result = self.emb_switch.get_assigned_devices() - self.assertEqual([self.ASSIGNED_MAC], result) + 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): diff --git a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_pci_lib.py b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_pci_lib.py index 5512ea95f..e8b267e2a 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_pci_lib.py +++ b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_pci_lib.py @@ -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, diff --git a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_sriov_nic_agent.py b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_sriov_nic_agent.py index 8ebc73ce5..b636f71bd 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_sriov_nic_agent.py +++ b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_sriov_nic_agent.py @@ -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)