From 02c16a0e603b6e75cca64df21dd86d9c30e4a6f6 Mon Sep 17 00:00:00 2001 From: Edan David Date: Mon, 22 Aug 2016 11:25:13 -0400 Subject: [PATCH] Reduce rpc calls in SR-IOV agent Use one update_port_list rpc call instead of update_port_up/update_port_down for each device separately. Closes-Bug: #1682979 Change-Id: I0a367712ff9410c2376b5b70c76806391bed3707 --- .../mech_sriov/agent/sriov_nic_agent.py | 34 ++--- .../mech_sriov/agent/test_sriov_nic_agent.py | 123 ++++++++++++++++-- 2 files changed, 132 insertions(+), 25 deletions(-) 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 4705bf2e410..ae4adb10586 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 @@ -252,20 +252,11 @@ class SriovNicSwitchAgent(object): device) except exc.SriovNicError: LOG.warning(_LW("Failed to set device %s state"), device) - return - if admin_state_up: - # update plugin about port status - self.plugin_rpc.update_device_up(self.context, - device, - self.agent_id, - cfg.CONF.host) - else: - self.plugin_rpc.update_device_down(self.context, - device, - self.agent_id, - cfg.CONF.host) + return False else: LOG.info(_LI("No device with MAC %s defined on agent."), device) + return False + return True def _update_network_ports(self, network_id, port_id, mac_pci_slot): self._clean_network_ports(mac_pci_slot) @@ -294,6 +285,8 @@ class SriovNicSwitchAgent(object): # resync is needed return True + devices_up = set() + devices_down = set() for device_details in devices_details_list: device = device_details['device'] LOG.debug("Port with MAC address %s is added", device) @@ -304,10 +297,14 @@ class SriovNicSwitchAgent(object): port_id = device_details['port_id'] profile = device_details['profile'] spoofcheck = device_details.get('port_security_enabled', True) - self.treat_device(device, - profile.get('pci_slot'), - device_details['admin_state_up'], - spoofcheck) + if self.treat_device(device, + profile.get('pci_slot'), + device_details['admin_state_up'], + spoofcheck): + if device_details['admin_state_up']: + devices_up.add(device) + else: + devices_down.add(device) self._update_network_ports(device_details['network_id'], port_id, (device, profile.get('pci_slot'))) @@ -315,6 +312,11 @@ class SriovNicSwitchAgent(object): else: LOG.info(_LI("Device with MAC %s not defined on plugin"), device) + self.plugin_rpc.update_device_list(self.context, + devices_up, + devices_down, + self.agent_id, + self.conf.host) return False def treat_devices_removed(self, devices): 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 f175ca50589..ecfc068e775 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 @@ -283,7 +283,108 @@ class TestSriovAgent(base.BaseTestCase): 'aa:bb:cc:dd:ee:ff', '1:2:3.0', False) - self.assertTrue(agent.plugin_rpc.update_device_up.called) + agent.plugin_rpc.update_device_list.assert_called_once_with( + mock.ANY, + set(['aa:bb:cc:dd:ee:ff']), + set(), + mock.ANY, + mock.ANY) + + def test_treat_devices_added_updated_multiple_admin_state_up_true(self): + agent = self.agent + mock_details = [{'device': 'aa:bb:cc:dd:ee:ff', + 'port_id': 'port123', + 'network_id': 'net123', + 'admin_state_up': True, + 'network_type': 'vlan', + 'segmentation_id': 100, + 'profile': {'pci_slot': '1:2:3.0'}, + 'physical_network': 'physnet1', + 'port_security_enabled': False}, + {'device': '11:22:33:44:55:66', + 'port_id': 'port321', + 'network_id': 'net123', + 'admin_state_up': True, + 'network_type': 'vlan', + 'segmentation_id': 100, + 'profile': {'pci_slot': '1:2:3.0'}, + 'physical_network': 'physnet1', + 'port_security_enabled': False}] + agent.plugin_rpc = mock.Mock() + agent.plugin_rpc.get_devices_details_list.return_value = mock_details + agent.eswitch_mgr = mock.Mock() + agent.eswitch_mgr.device_exists.return_value = True + agent.set_device_state = mock.Mock() + agent.set_device_spoofcheck = mock.Mock() + resync_needed = agent.treat_devices_added_updated( + set(['aa:bb:cc:dd:ee:ff', + '11:22:33:44:55:66'])) + self.assertFalse(resync_needed) + calls = [mock.call('aa:bb:cc:dd:ee:ff', '1:2:3.0'), + mock.call('11:22:33:44:55:66', '1:2:3.0')] + agent.eswitch_mgr.device_exists.assert_has_calls(calls, any_order=True) + calls = [mock.call('aa:bb:cc:dd:ee:ff', '1:2:3.0', True), + mock.call('11:22:33:44:55:66', '1:2:3.0', True)] + agent.eswitch_mgr.set_device_state.assert_has_calls(calls, + any_order=True) + calls = [mock.call('aa:bb:cc:dd:ee:ff', '1:2:3.0', False), + mock.call('11:22:33:44:55:66', '1:2:3.0', False)] + agent.eswitch_mgr.set_device_spoofcheck.assert_has_calls(calls, + any_order=True) + agent.plugin_rpc.update_device_list.assert_called_once_with( + mock.ANY, + set(['aa:bb:cc:dd:ee:ff', '11:22:33:44:55:66']), + set(), + mock.ANY, + mock.ANY) + + def test_treat_devices_added_updated_multiple_admin_states(self): + agent = self.agent + mock_details = [{'device': 'aa:bb:cc:dd:ee:ff', + 'port_id': 'port123', + 'network_id': 'net123', + 'admin_state_up': True, + 'network_type': 'vlan', + 'segmentation_id': 100, + 'profile': {'pci_slot': '1:2:3.0'}, + 'physical_network': 'physnet1', + 'port_security_enabled': False}, + {'device': '11:22:33:44:55:66', + 'port_id': 'port321', + 'network_id': 'net123', + 'admin_state_up': False, + 'network_type': 'vlan', + 'segmentation_id': 100, + 'profile': {'pci_slot': '1:2:3.0'}, + 'physical_network': 'physnet1', + 'port_security_enabled': False}] + agent.plugin_rpc = mock.Mock() + agent.plugin_rpc.get_devices_details_list.return_value = mock_details + agent.eswitch_mgr = mock.Mock() + agent.eswitch_mgr.device_exists.return_value = True + agent.set_device_state = mock.Mock() + agent.set_device_spoofcheck = mock.Mock() + resync_needed = agent.treat_devices_added_updated( + set(['aa:bb:cc:dd:ee:ff', + '11:22:33:44:55:66'])) + self.assertFalse(resync_needed) + calls = [mock.call('aa:bb:cc:dd:ee:ff', '1:2:3.0'), + mock.call('11:22:33:44:55:66', '1:2:3.0')] + agent.eswitch_mgr.device_exists.assert_has_calls(calls, any_order=True) + calls = [mock.call('aa:bb:cc:dd:ee:ff', '1:2:3.0', True), + mock.call('11:22:33:44:55:66', '1:2:3.0', False)] + agent.eswitch_mgr.set_device_state.assert_has_calls(calls, + any_order=True) + calls = [mock.call('aa:bb:cc:dd:ee:ff', '1:2:3.0', False), + mock.call('11:22:33:44:55:66', '1:2:3.0', False)] + agent.eswitch_mgr.set_device_spoofcheck.assert_has_calls(calls, + any_order=True) + agent.plugin_rpc.update_device_list.assert_called_once_with( + mock.ANY, + set(['aa:bb:cc:dd:ee:ff']), + set(['11:22:33:44:55:66']), + mock.ANY, + mock.ANY) def test_treat_device_ip_link_state_not_supported(self): agent = self.agent @@ -294,9 +395,8 @@ class TestSriovAgent(base.BaseTestCase): exceptions.IpCommandOperationNotSupportedError( dev_name='aa:bb:cc:dd:ee:ff')) - agent.treat_device('aa:bb:cc:dd:ee:ff', '1:2:3:0', - admin_state_up=True) - self.assertTrue(agent.plugin_rpc.update_device_up.called) + self.assertTrue(agent.treat_device('aa:bb:cc:dd:ee:ff', '1:2:3:0', + admin_state_up=True)) def test_treat_device_set_device_state_exception(self): agent = self.agent @@ -306,9 +406,8 @@ class TestSriovAgent(base.BaseTestCase): agent.eswitch_mgr.set_device_state.side_effect = ( exceptions.SriovNicError()) - agent.treat_device('aa:bb:cc:dd:ee:ff', '1:2:3:0', - admin_state_up=True) - self.assertFalse(agent.plugin_rpc.update_device_up.called) + self.assertFalse(agent.treat_device('aa:bb:cc:dd:ee:ff', '1:2:3:0', + admin_state_up=True)) def test_treat_devices_added_updated_admin_state_up_false(self): agent = self.agent @@ -323,11 +422,17 @@ class TestSriovAgent(base.BaseTestCase): agent.plugin_rpc = mock.Mock() agent.plugin_rpc.get_devices_details_list.return_value = [mock_details] agent.remove_port_binding = mock.Mock() + agent.eswitch_mgr = mock.Mock() + agent.eswitch_mgr.device_exists.return_value = True resync_needed = agent.treat_devices_added_updated( set(['aa:bb:cc:dd:ee:ff'])) - self.assertFalse(resync_needed) - self.assertFalse(agent.plugin_rpc.update_device_up.called) + agent.plugin_rpc.update_device_list.assert_called_once_with( + mock.ANY, + set(), + set(['aa:bb:cc:dd:ee:ff']), + mock.ANY, + mock.ANY) def test_update_and_clean_network_ports(self): network_id1 = 'network_id1'