nmstate/SOURCES/BZ_1908724-sriov-use-verifi...

186 lines
6.2 KiB
Diff

From 1d0656c4197f0119d156b0df7b13bffeb5c46861 Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
Date: Mon, 4 Jan 2021 11:37:18 +0800
Subject: [PATCH] sriov: Use verification retry to wait VF been created
When reactivating i40e interface with SR-IOV enabled, the kernel
takes some time(1 seconds or more in my test) to get the VF interface
ready in kernel. So at the time of libnmstate returns with success, the
VF interface might not be ready for use yet.
To fix that, we include VF interfaces in desire state when PV is
changed/desired. The verification retry will wait the VF to be ready for
use.
Unit test case and integration test case included.
Also fixed SRIOV integration test cases which are now all passing on i40e
NIC.
To test on real SRIOV NIC:
cd tests/integration/
sudo env TEST_REAL_NIC=ens1f1 pytest-3 sriov_test.py -vvv
Signed-off-by: Gris Ge <fge@redhat.com>
---
libnmstate/ifaces/ethernet.py | 28 ++++
libnmstate/ifaces/ifaces.py | 23 +++
libnmstate/nm/sriov.py | 2 +-
libnmstate/nm/wired.py | 19 ++-
tests/integration/sriov_test.py | 242 ++++++++++++++++++++++----------
tests/lib/nm/wired_test.py | 5 +
6 files changed, 231 insertions(+), 88 deletions(-)
diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py
index b346c36..644fe6d 100644
--- a/libnmstate/ifaces/ethernet.py
+++ b/libnmstate/ifaces/ethernet.py
@@ -18,6 +18,9 @@
#
from libnmstate.schema import Ethernet
+from libnmstate.schema import Interface
+from libnmstate.schema import InterfaceType
+from libnmstate.schema import InterfaceState
from .base_iface import BaseIface
@@ -46,6 +49,31 @@ class EthernetIface(BaseIface):
_capitalize_sriov_vf_mac(state)
return state
+ @property
+ def sriov_total_vfs(self):
+ return (
+ self.raw.get(Ethernet.CONFIG_SUBTREE, {})
+ .get(Ethernet.SRIOV_SUBTREE, {})
+ .get(Ethernet.SRIOV.TOTAL_VFS, 0)
+ )
+
+ def create_sriov_vf_ifaces(self):
+ return [
+ EthernetIface(
+ {
+ # According to manpage of systemd.net-naming-scheme(7),
+ # SRIOV VF interface will have v{slot} in device name.
+ # Currently, nmstate has no intention to support
+ # user-defined udev rule on SRIOV interface naming policy.
+ Interface.NAME: f"{self.name}v{i}",
+ Interface.TYPE: InterfaceType.ETHERNET,
+ # VF will be in DOWN state initialy.
+ Interface.STATE: InterfaceState.DOWN,
+ }
+ )
+ for i in range(0, self.sriov_total_vfs)
+ ]
+
def _capitalize_sriov_vf_mac(state):
vfs = (
diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py
index 703e672..7723f43 100644
--- a/libnmstate/ifaces/ifaces.py
+++ b/libnmstate/ifaces/ifaces.py
@@ -97,6 +97,7 @@ class Ifaces:
self._ifaces[iface.name] = iface
self._create_virtual_slaves()
+ self._create_sriov_vfs_when_changed()
self._validate_unknown_slaves()
self._validate_unknown_parent()
self._gen_metadata()
@@ -124,6 +125,28 @@ class Ifaces:
for iface in new_ifaces:
self._ifaces[iface.name] = iface
+ def _create_sriov_vfs_when_changed(self):
+ """
+ When plugin set the TOTAL_VFS of PF, it might take 1 seconds or
+ more to have the VFs to be ready.
+ Nmstate should use verification retry to make sure VFs are full ready.
+ To do that, we include VFs into desire state.
+ """
+ new_ifaces = []
+ for iface in self._ifaces.values():
+ if (
+ iface.is_up
+ and (iface.is_desired or iface.is_changed)
+ and iface.type == InterfaceType.ETHERNET
+ and iface.sriov_total_vfs > 0
+ ):
+ for new_iface in iface.create_sriov_vf_ifaces():
+ if new_iface.name not in self._ifaces:
+ new_iface.mark_as_desired()
+ new_ifaces.append(new_iface)
+ for new_iface in new_ifaces:
+ self._ifaces[new_iface.name] = new_iface
+
def _pre_edit_validation_and_cleanup(self):
self._validate_over_booked_slaves()
self._validate_vlan_mtu()
diff --git a/libnmstate/nm/sriov.py b/libnmstate/nm/sriov.py
index f544732..25b150c 100644
--- a/libnmstate/nm/sriov.py
+++ b/libnmstate/nm/sriov.py
@@ -68,7 +68,7 @@ def create_setting(context, iface_state, base_con_profile):
sriov_config = iface_state.get(Ethernet.CONFIG_SUBTREE, {}).get(
Ethernet.SRIOV_SUBTREE
)
- if sriov_config:
+ if sriov_config and sriov_config.get(Ethernet.SRIOV.TOTAL_VFS):
if not _has_sriov_capability(context, ifname):
raise NmstateNotSupportedError(
f"Interface '{ifname}' does not support SR-IOV"
diff --git a/libnmstate/nm/wired.py b/libnmstate/nm/wired.py
index 64662ac..5fea2a5 100644
--- a/libnmstate/nm/wired.py
+++ b/libnmstate/nm/wired.py
@@ -162,15 +162,18 @@ def _get_mac_address_from_sysfs(ifname):
def _get_ethernet_info(device, iface):
+
ethernet = {}
+ sriov_info = sriov.get_info(device)
+ if sriov_info:
+ ethernet.update(sriov_info)
+
try:
speed = int(device.get_speed())
if speed > 0:
ethernet[Ethernet.SPEED] = speed
- else:
- return None
except AttributeError:
- return None
+ pass
ethtool_results = minimal_ethtool(iface)
auto_setting = ethtool_results[Ethernet.AUTO_NEGOTIATION]
@@ -178,17 +181,11 @@ def _get_ethernet_info(device, iface):
ethernet[Ethernet.AUTO_NEGOTIATION] = True
elif auto_setting is False:
ethernet[Ethernet.AUTO_NEGOTIATION] = False
- else:
- return None
duplex_setting = ethtool_results[Ethernet.DUPLEX]
if duplex_setting in [Ethernet.HALF_DUPLEX, Ethernet.FULL_DUPLEX]:
ethernet[Ethernet.DUPLEX] = duplex_setting
- else:
- return None
-
- sriov_info = sriov.get_info(device)
- if sriov_info:
- ethernet.update(sriov_info)
+ if not ethernet:
+ return None
return ethernet
--
2.25.4