Blob Blame History Raw
From 80c97b27707b036f0a54988ade4bda3ccb342b34 Mon Sep 17 00:00:00 2001
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
Date: Mon, 22 Feb 2021 12:03:11 +0100
Subject: [PATCH 1/2] SR-IOV: increase the verification timeout if SR-IOV is
 present

Certain drivers like i40e take a long time to modify the VFs in the
kernel. Nmstate is timing out on verification because of that. In order
to fix this, nmstate is incresing the verification time if SR-IOV is
present on the desired state.

Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
Signed-off-by: Gris Ge <fge@redhat.com>
---
 libnmstate/ifaces/ethernet.py |  6 ++++++
 libnmstate/netapplier.py      | 18 +++++++++++++++++-
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py
index 292b7bc..ca8501b 100644
--- a/libnmstate/ifaces/ethernet.py
+++ b/libnmstate/ifaces/ethernet.py
@@ -65,6 +65,12 @@ class EthernetIface(BaseIface):
     def is_peer(self):
         return self._is_peer
 
+    @property
+    def is_sriov(self):
+        return self.raw.get(Ethernet.CONFIG_SUBTREE, {}).get(
+            Ethernet.SRIOV_SUBTREE
+        )
+
     def create_sriov_vf_ifaces(self):
         return [
             EthernetIface(
diff --git a/libnmstate/netapplier.py b/libnmstate/netapplier.py
index cf208d1..3c5759b 100644
--- a/libnmstate/netapplier.py
+++ b/libnmstate/netapplier.py
@@ -24,6 +24,7 @@ import time
 
 from libnmstate import validator
 from libnmstate.error import NmstateVerificationError
+from libnmstate.schema import InterfaceType
 
 from .nmstate import create_checkpoints
 from .nmstate import destroy_checkpoints
@@ -37,6 +38,7 @@ from .version import get_version
 MAINLOOP_TIMEOUT = 35
 VERIFY_RETRY_INTERNAL = 1
 VERIFY_RETRY_TIMEOUT = 5
+VERIFY_RETRY_TIMEOUT_INCREASE = 4
 
 
 def apply(
@@ -109,7 +111,13 @@ def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk):
         plugin.apply_changes(net_state, save_to_disk)
     verified = False
     if verify_change:
-        for _ in range(VERIFY_RETRY_TIMEOUT):
+        if _net_state_contains_sriov_interface(net_state):
+            # If SR-IOV is present, the verification timeout is being increased
+            # to avoid timeouts due to slow drivers like i40e.
+            verify_retry = VERIFY_RETRY_TIMEOUT * VERIFY_RETRY_TIMEOUT_INCREASE
+        else:
+            verify_retry = VERIFY_RETRY_TIMEOUT
+        for _ in range(verify_retry):
             try:
                 _verify_change(plugins, net_state)
                 verified = True
@@ -120,6 +128,14 @@ def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk):
             _verify_change(plugins, net_state)
 
 
+def _net_state_contains_sriov_interface(net_state):
+    for iface in net_state.ifaces.all_kernel_ifaces.values():
+        if iface.type == InterfaceType.ETHERNET and iface.is_sriov:
+            return True
+
+    return False
+
+
 def _verify_change(plugins, net_state):
     current_state = show_with_plugins(plugins)
     net_state.verify(current_state)
-- 
2.27.0


From 439fe3a51a82060c5b62974c6c9fbdf403c4196b Mon Sep 17 00:00:00 2001
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
Date: Mon, 22 Feb 2021 13:33:06 +0100
Subject: [PATCH 2/2] SR-IOV: fail on verification if `total_vfs` does not
 match vfs len

Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
Signed-off-by: Gris Ge <fge@redhat.com>
---
 libnmstate/ifaces/ethernet.py | 11 +++++++++++
 libnmstate/ifaces/ifaces.py   | 14 ++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py
index ca8501b..55772ce 100644
--- a/libnmstate/ifaces/ethernet.py
+++ b/libnmstate/ifaces/ethernet.py
@@ -61,6 +61,14 @@ class EthernetIface(BaseIface):
             .get(Ethernet.SRIOV.TOTAL_VFS, 0)
         )
 
+    @property
+    def sriov_vfs(self):
+        return (
+            self.raw.get(Ethernet.CONFIG_SUBTREE, {})
+            .get(Ethernet.SRIOV_SUBTREE, {})
+            .get(Ethernet.SRIOV.VFS_SUBTREE, [])
+        )
+
     @property
     def is_peer(self):
         return self._is_peer
@@ -108,6 +116,9 @@ class EthernetIface(BaseIface):
             for i in range(self.sriov_total_vfs, old_sriov_total_vfs)
         ]
 
+    def check_total_vfs_matches_vf_list(self, total_vfs):
+        return total_vfs == len(self.sriov_vfs)
+
 
 def _capitalize_sriov_vf_mac(state):
     vfs = (
diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py
index 44c9e61..6c94a98 100644
--- a/libnmstate/ifaces/ifaces.py
+++ b/libnmstate/ifaces/ifaces.py
@@ -238,6 +238,8 @@ class Ifaces:
                     if new_iface.name not in self._kernel_ifaces:
                         new_iface.mark_as_desired()
                         new_ifaces.append(new_iface)
+                    else:
+                        self._kernel_ifaces[new_iface.name].mark_as_desired()
         for new_iface in new_ifaces:
             self._kernel_ifaces[new_iface.name] = new_iface
 
@@ -656,6 +658,18 @@ class Ifaces:
                                 cur_iface.state_for_verify(),
                             )
                         )
+                    elif (
+                        iface.type == InterfaceType.ETHERNET and iface.is_sriov
+                    ):
+                        if not cur_iface.check_total_vfs_matches_vf_list(
+                            iface.sriov_total_vfs
+                        ):
+                            raise NmstateVerificationError(
+                                "The NIC exceeded the waiting time for "
+                                "verification and it is failing because "
+                                "the `total_vfs` does not match the VF "
+                                "list length."
+                            )
 
     def gen_dns_metadata(self, dns_state, route_state):
         iface_metadata = dns_state.gen_metadata(self, route_state)
-- 
2.27.0