]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
sriov: implement spoofchecking configuration
authorRoman Bogorodskiy <rbogorodskiy@mirantis.com>
Thu, 16 Apr 2015 07:07:55 +0000 (09:07 +0200)
committerRoman Bogorodskiy <rbogorodskiy@mirantis.com>
Wed, 29 Jul 2015 17:38:25 +0000 (19:38 +0200)
- Make sriov agent to set the spoofchecking on VFs
  according to port_security_enabled attribute of the port.
- Extend vf management sanity check to probe spoof checking
  capability

Implements: blueprint sriov-spoofchk
Change-Id: I4d1060be26ee6cbd7d766c2bde364f694533de69

neutron/cmd/sanity/checks.py
neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py
neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py
neutron/plugins/ml2/drivers/mech_sriov/agent/sriov_nic_agent.py
neutron/tests/unit/agent/linux/test_ip_link_support.py
neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py
neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_pci_lib.py
neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_sriov_nic_agent.py

index 5d90ad9c306e0d83b1f69b925bcb7ffd5125e94a..37f0947f2db31763cc3e710aa91b67532d74b6d5 100644 (file)
@@ -127,13 +127,17 @@ def arp_header_match_supported():
 
 
 def vf_management_supported():
+    required_caps = (
+        ip_link_support.IpLinkConstants.IP_LINK_CAPABILITY_STATE,
+        ip_link_support.IpLinkConstants.IP_LINK_CAPABILITY_SPOOFCHK)
     try:
         vf_section = ip_link_support.IpLinkSupport.get_vf_mgmt_section()
-        if not ip_link_support.IpLinkSupport.vf_mgmt_capability_supported(
-                vf_section,
-                ip_link_support.IpLinkConstants.IP_LINK_CAPABILITY_STATE):
-            LOG.debug("ip link command does not support vf capability")
-            return False
+        for cap in required_caps:
+            if not ip_link_support.IpLinkSupport.vf_mgmt_capability_supported(
+                   vf_section, cap):
+                LOG.debug("ip link command does not support "
+                          "vf capability '%(cap)s'", cap)
+                return False
     except ip_link_support.UnsupportedIpLinkCommand:
         LOG.exception(_LE("Unexpected exception while checking supported "
                           "ip link command"))
index f8f4bd846beacf18878de4a94e316f3f0d04fee6..8664769771f1e63aac22751dc25a85188b0417d5 100644 (file)
@@ -164,6 +164,17 @@ class EmbSwitch(object):
             raise exc.InvalidPciSlotError(pci_slot=pci_slot)
         return self.pci_dev_wrapper.set_vf_state(vf_index, state)
 
+    def set_device_spoofcheck(self, pci_slot, enabled):
+        """Set device spoofchecking
+
+        @param pci_slot: Virtual Function address
+        @param enabled: True to enable spoofcheck, False to disable
+        """
+        vf_index = self.pci_slot_map.get(pci_slot)
+        if vf_index is None:
+            raise exc.InvalidPciSlotError(pci_slot=pci_slot)
+        return self.pci_dev_wrapper.set_vf_spoofcheck(vf_index, enabled)
+
     def get_pci_device(self, pci_slot):
         """Get mac address for given Virtual Function address
 
@@ -252,6 +263,19 @@ class ESwitchManager(object):
             embedded_switch.set_device_state(pci_slot,
                                              admin_state_up)
 
+    def set_device_spoofcheck(self, device_mac, pci_slot, enabled):
+        """Set device spoofcheck
+
+        Sets device spoofchecking (enabled or disabled)
+        @param device_mac: device mac
+        @param pci_slot: pci slot
+        @param enabled: device spoofchecking
+        """
+        embedded_switch = self._get_emb_eswitch(device_mac, pci_slot)
+        if embedded_switch:
+            embedded_switch.set_device_spoofcheck(pci_slot,
+                                                  enabled)
+
     def _discover_devices(self, device_mappings, exclude_devices):
         """Discover which Virtual functions to manage.
 
index 05fc0d2f85987eea354fe1c42cc80d8d8f558c9c..0869b549ad592cf158a993be2a588dde440efecf 100644 (file)
@@ -106,6 +106,22 @@ class PciDeviceIPWrapper(ip_lib.IPWrapper):
             raise exc.IpCommandError(dev_name=self.dev_name,
                                      reason=e)
 
+    def set_vf_spoofcheck(self, vf_index, enabled):
+        """sets vf spoofcheck
+
+        @param vf_index: vf index
+        @param enabled: True to enable spoof checking,
+                        False to disable
+        """
+        setting = "on" if enabled else "off"
+
+        try:
+            self._as_root('', "link", ("set", self.dev_name, "vf",
+                                       str(vf_index), "spoofchk", setting))
+        except Exception as e:
+            raise exc.IpCommandError(dev_name=self.dev_name,
+                                     reason=str(e))
+
     def _get_vf_link_show(self, vf_list, link_show_out):
         """Get link show output for VFs
 
index 54ff293e8d4e49e660ce725b9f0f7de08d367b43..e1dd7247bfbb3dc5b5120b93b1fb868668cc0bc2 100644 (file)
@@ -33,7 +33,7 @@ from neutron.common import constants as n_constants
 from neutron.common import topics
 from neutron.common import utils as n_utils
 from neutron import context
-from neutron.i18n import _LE, _LI
+from neutron.i18n import _LE, _LI, _LW
 from neutron.plugins.ml2.drivers.mech_sriov.agent.common import config  # noqa
 from neutron.plugins.ml2.drivers.mech_sriov.agent.common \
     import exceptions as exc
@@ -169,8 +169,17 @@ class SriovNicSwitchAgent(object):
         # If one of the above operations fails => resync with plugin
         return (resync_a | resync_b)
 
-    def treat_device(self, device, pci_slot, admin_state_up):
+    def treat_device(self, device, pci_slot, admin_state_up, spoofcheck=True):
         if self.eswitch_mgr.device_exists(device, pci_slot):
+            try:
+                self.eswitch_mgr.set_device_spoofcheck(device, pci_slot,
+                                                       spoofcheck)
+            except Exception:
+                LOG.warning(_LW("Failed to set spoofcheck for device %s"),
+                            device)
+            LOG.info(_LI("Device %(device)s spoofcheck %(spoofcheck)s"),
+                     {"device": device, "spoofcheck": spoofcheck})
+
             try:
                 self.eswitch_mgr.set_device_state(device, pci_slot,
                                                   admin_state_up)
@@ -210,9 +219,11 @@ class SriovNicSwitchAgent(object):
                 LOG.info(_LI("Port %(device)s updated. Details: %(details)s"),
                          {'device': device, 'details': device_details})
                 profile = device_details['profile']
+                spoofcheck = device_details.get('port_security_enabled', True)
                 self.treat_device(device_details['device'],
                                   profile.get('pci_slot'),
-                                  device_details['admin_state_up'])
+                                  device_details['admin_state_up'],
+                                  spoofcheck)
             else:
                 LOG.info(_LI("Device with MAC %s not defined on plugin"),
                          device)
index 0a843e7d29d172f9525f6202bc5d7f1cd6fb7043..cf29530b23b7972347c240c3dbf24de852dd4528 100644 (file)
@@ -90,6 +90,8 @@ TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
 TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can }
     """
 
+    IP_LINK_HELP_NO_SPOOFCHK = IP_LINK_HELP_NO_STATE
+
     IP_LINK_HELP_NO_VF = """Usage: ip link set DEVICE { up | down |
                              arp { on | off } |
                              dynamic { on | off } |
@@ -134,6 +136,12 @@ TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can }
             expected=False,
             stderr=self.IP_LINK_HELP_NO_STATE)
 
+    def test_vf_mgmt_no_spoofchk(self):
+        self._test_capability(
+            ip_link.IpLinkConstants.IP_LINK_CAPABILITY_SPOOFCHK,
+            expected=False,
+            stderr=self.IP_LINK_HELP_NO_SPOOFCHK)
+
     def test_vf_mgmt_no_vf(self):
         self._test_capability(
             ip_link.IpLinkConstants.IP_LINK_CAPABILITY_STATE,
index 72c5da0c32fce3e506ccf7b9fa1ed298152cf008..a9a5b3a67a906ec3465a83706ace3c8a65fa9ac4 100644 (file)
@@ -246,6 +246,20 @@ class TestEmbSwitch(base.BaseTestCase):
                               self.emb_switch.set_device_state,
                               self.WRONG_PCI_SLOT, True)
 
+    def test_set_device_spoofcheck_ok(self):
+        with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
+                        "PciDeviceIPWrapper.set_vf_spoofcheck") as \
+                                set_vf_spoofcheck_mock:
+            self.emb_switch.set_device_spoofcheck(self.PCI_SLOT, True)
+            self.assertTrue(set_vf_spoofcheck_mock.called)
+
+    def test_set_device_spoofcheck_fail(self):
+        with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
+                        "PciDeviceIPWrapper.set_vf_spoofcheck"):
+            self.assertRaises(exc.InvalidPciSlotError,
+                              self.emb_switch.set_device_spoofcheck,
+                              self.WRONG_PCI_SLOT, True)
+
     def test_get_pci_device(self):
         with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
                         "PciDeviceIPWrapper.get_assigned_macs",
index 62a10f0fba09ba5a97b3c2e809c8156d9c3e89d4..de8a6652b66e65b6e3f1544bcd8f17e9ee89bbe9 100644 (file)
@@ -99,3 +99,18 @@ class TestPciLib(base.BaseTestCase):
                               self.pci_wrapper.set_vf_state,
                               self.VF_INDEX,
                               True)
+
+    def test_set_vf_spoofcheck(self):
+        with mock.patch.object(self.pci_wrapper, "_execute"):
+            result = self.pci_wrapper.set_vf_spoofcheck(self.VF_INDEX,
+                                                        True)
+            self.assertIsNone(result)
+
+    def test_set_vf_spoofcheck_fail(self):
+        with mock.patch.object(self.pci_wrapper,
+                               "_execute") as mock_exec:
+            mock_exec.side_effect = Exception()
+            self.assertRaises(exc.IpCommandError,
+                              self.pci_wrapper.set_vf_spoofcheck,
+                              self.VF_INDEX,
+                              True)
index 9729d3fb7be247e27bb5b5b745af7d7bd2582287..ccbb04435ae3c257cc13a96e165c4d99273f9247 100644 (file)
@@ -178,12 +178,14 @@ class TestSriovAgent(base.BaseTestCase):
                         'network_type': 'vlan',
                         'segmentation_id': 100,
                         'profile': {'pci_slot': '1:2:3.0'},
-                        'physical_network': 'physnet1'}
+                        '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']))
 
@@ -194,6 +196,10 @@ class TestSriovAgent(base.BaseTestCase):
                                         'aa:bb:cc:dd:ee:ff',
                                         '1:2:3.0',
                                         True)
+        agent.eswitch_mgr.set_device_spoofcheck.assert_called_with(
+                                        'aa:bb:cc:dd:ee:ff',
+                                        '1:2:3.0',
+                                        False)
         self.assertTrue(agent.plugin_rpc.update_device_up.called)
 
     def test_treat_devices_added_updated_admin_state_up_false(self):