186 lines
6.2 KiB
Diff
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
|
||
|
|