Blob Blame History Raw
From c55d39e8485a26490afc36d71fd9d20528ab6fd2 Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
Date: Thu, 18 Feb 2021 18:01:17 +0800
Subject: [PATCH 1/5] SRIOV: Remove VF interface when total-vfs decrease

When `Ethernet.SRIOV.TOTAL_VFS` decrease, we should mark removed VF
interface as absent.

Both integration and unit test cases have been include.
The integration test has been tested on real SRIOV hardware.

Signed-off-by: Gris Ge <fge@redhat.com>
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
---
 libnmstate/ifaces/base_iface.py |  5 +++++
 libnmstate/ifaces/ethernet.py   | 20 ++++++++++++++++++
 libnmstate/ifaces/ifaces.py     | 24 +++++++++++++++++++++
 tests/integration/sriov_test.py | 37 +++++++++++++++++++++++++++++++++
 4 files changed, 86 insertions(+)

diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py
index 564d583a..b4ade867 100644
--- a/libnmstate/ifaces/base_iface.py
+++ b/libnmstate/ifaces/base_iface.py
@@ -177,6 +177,11 @@ class BaseIface:
     def mark_as_desired(self):
         self._is_desired = True
 
+    def mark_as_absent_by_desire(self):
+        self.mark_as_desired()
+        self._info[Interface.STATE] = InterfaceState.ABSENT
+        self._origin_info[Interface.STATE] = InterfaceState.ABSENT
+
     def to_dict(self):
         return deepcopy(self._info)
 
diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py
index 644fe6dd..3e1bdc5d 100644
--- a/libnmstate/ifaces/ethernet.py
+++ b/libnmstate/ifaces/ethernet.py
@@ -74,6 +74,26 @@ class EthernetIface(BaseIface):
             for i in range(0, self.sriov_total_vfs)
         ]
 
+    def remove_vfs_entry_when_total_vfs_decreased(self):
+        vfs_count = len(
+            self._info[Ethernet.CONFIG_SUBTREE]
+            .get(Ethernet.SRIOV_SUBTREE, {})
+            .get(Ethernet.SRIOV.VFS_SUBTREE, [])
+        )
+        if vfs_count > self.sriov_total_vfs:
+            [
+                self._info[Ethernet.CONFIG_SUBTREE][Ethernet.SRIOV_SUBTREE][
+                    Ethernet.SRIOV.VFS_SUBTREE
+                ].pop()
+                for _ in range(self.sriov_total_vfs, vfs_count)
+            ]
+
+    def get_delete_vf_interface_names(self, old_sriov_total_vfs):
+        return [
+            f"{self.name}v{i}"
+            for i in range(self.sriov_total_vfs, old_sriov_total_vfs)
+        ]
+
 
 def _capitalize_sriov_vf_mac(state):
     vfs = (
diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py
index ee75125d..67ab91c4 100644
--- a/libnmstate/ifaces/ifaces.py
+++ b/libnmstate/ifaces/ifaces.py
@@ -99,6 +99,7 @@ class Ifaces:
             self._create_virtual_slaves()
             self._create_sriov_vfs_when_changed()
             self._validate_unknown_slaves()
+            self._mark_vf_interface_as_absent_when_sriov_vf_decrease()
             self._validate_unknown_parent()
             self._gen_metadata()
             for iface in self._ifaces.values():
@@ -147,6 +148,29 @@ class Ifaces:
         for new_iface in new_ifaces:
             self._ifaces[new_iface.name] = new_iface
 
+    def _mark_vf_interface_as_absent_when_sriov_vf_decrease(self):
+        """
+        When SRIOV TOTAL_VFS decreased, we should mark certain VF interfaces
+        as absent and also remove the entry in `Ethernet.SRIOV.VFS_SUBTREE`.
+        """
+        for iface_name, iface in self._ifaces.items():
+            if iface.type != InterfaceType.ETHERNET or not iface.is_up:
+                continue
+            if iface_name not in self.current_ifaces:
+                continue
+            cur_iface = self.current_ifaces[iface_name]
+            if (
+                cur_iface.sriov_total_vfs != 0
+                and iface.sriov_total_vfs < cur_iface.sriov_total_vfs
+            ):
+                iface.remove_vfs_entry_when_total_vfs_decreased()
+                for vf_name in iface.get_delete_vf_interface_names(
+                    cur_iface.sriov_total_vfs
+                ):
+                    vf_iface = self._ifaces.get(vf_name)
+                    if vf_iface:
+                        vf_iface.mark_as_absent_by_desire()
+
     def _pre_edit_validation_and_cleanup(self):
         self._validate_over_booked_slaves()
         self._validate_vlan_mtu()
-- 
2.29.2