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