diff --git a/SOURCES/BZ_1932247-nm-Don-t-touch-unmanaged-interface-unless-desired.patch b/SOURCES/BZ_1932247-nm-Don-t-touch-unmanaged-interface-unless-desired.patch deleted file mode 100644 index ea46af7..0000000 --- a/SOURCES/BZ_1932247-nm-Don-t-touch-unmanaged-interface-unless-desired.patch +++ /dev/null @@ -1,223 +0,0 @@ -From ccdcd8f86544a6364109a0c0142d05a5afacf64e Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Tue, 2 Mar 2021 15:31:20 +0800 -Subject: [PATCH] nm: Don't touch unmanaged interface unless desired - -We should ignore NetworkManager unmanaged interface when applying and -verifying unless certain interface listed in desired state explicitly. - -Introduced new plugin interface -`NmstatePlugin.get_ignored_kernel_interface_names()` where plugin may -include a list of interface names which should be ignored during -verification stage. - -Integration test case added to simulate CNV usage on partial editing -a linux bridge holding NM unmanaged interface. - -Signed-off-by: Gris Ge ---- - libnmstate/ifaces/base_iface.py | 3 ++ - libnmstate/ifaces/ifaces.py | 26 ++++++++-------- - libnmstate/netapplier.py | 6 ++++ - libnmstate/nispor/plugin.py | 6 +++- - libnmstate/nm/plugin.py | 25 ++++++++++++++++ - libnmstate/plugin.py | 7 +++++ - tests/integration/linux_bridge_test.py | 8 +---- - tests/integration/nm/linux_bridge_test.py | 36 ++++++++++++++++++++++- - 8 files changed, 95 insertions(+), 22 deletions(-) - -diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py -index 227c1d20..e3f2a1ca 100644 ---- a/libnmstate/ifaces/base_iface.py -+++ b/libnmstate/ifaces/base_iface.py -@@ -322,6 +322,9 @@ class BaseIface: - def mark_as_up(self): - self.raw[Interface.STATE] = InterfaceState.UP - -+ def mark_as_ignored(self): -+ self.raw[Interface.STATE] = InterfaceState.IGNORE -+ - @property - def is_controller(self): - return False -diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py -index 6c94a986..efa24aa3 100644 ---- a/libnmstate/ifaces/ifaces.py -+++ b/libnmstate/ifaces/ifaces.py -@@ -95,7 +95,6 @@ class Ifaces: - self._kernel_ifaces = {} - self._user_space_ifaces = _UserSpaceIfaces() - self._cur_user_space_ifaces = _UserSpaceIfaces() -- self._ignored_ifaces = set() - if cur_iface_infos: - for iface_info in cur_iface_infos: - cur_iface = _to_specific_iface_obj(iface_info, save_to_disk) -@@ -143,10 +142,6 @@ class Ifaces: - ): - # Ignore interface with unknown type - continue -- if iface.is_ignore: -- self._ignored_ifaces.add( -- (iface.name, iface.type, iface.is_user_space_only) -- ) - if cur_iface: - iface.merge(cur_iface) - iface.mark_as_desired() -@@ -169,6 +164,10 @@ class Ifaces: - - self._pre_edit_validation_and_cleanup() - -+ @property -+ def _ignored_ifaces(self): -+ return [iface for iface in self.all_ifaces() if iface.is_ignore] -+ - def _apply_copy_mac_from(self): - for iface in self.all_kernel_ifaces.values(): - if iface.type not in ( -@@ -284,7 +283,7 @@ class Ifaces: - if not defiend in desire state - """ - for iface in self.all_ifaces(): -- if iface.is_up and iface.is_controller: -+ if iface.is_desired and iface.is_up and iface.is_controller: - for port_name in iface.port: - port_iface = self._kernel_ifaces[port_name] - if not port_iface.is_desired and not port_iface.is_up: -@@ -550,13 +549,14 @@ class Ifaces: - return None - - def _remove_iface(self, iface_name, iface_type): -- cur_iface = self._cur_kernel_ifaces.get(iface_name, iface_type) -+ cur_iface = self._user_space_ifaces.get(iface_name, iface_type) - if cur_iface: - self._user_space_ifaces.remove(cur_iface) - else: - cur_iface = self._kernel_ifaces.get(iface_name) - if ( -- iface_type -+ cur_iface -+ and iface_type - and iface_type != InterfaceType.UNKNOWN - and iface_type == cur_iface.type - ): -@@ -813,14 +813,14 @@ class Ifaces: - port_controller_map[port_name] = iface.name - - def _remove_ignore_interfaces(self, ignored_ifaces): -- for iface_name, iface_type, _ in ignored_ifaces: -- self._remove_iface(iface_name, iface_type) -+ for iface in ignored_ifaces: -+ self._remove_iface(iface.name, iface.type) - - # Only kernel interface can be used as port - ignored_kernel_iface_names = set( -- iface_name -- for iface_name, _, is_user_space_only in ignored_ifaces -- if not is_user_space_only -+ iface.name -+ for iface in ignored_ifaces -+ if not iface.is_user_space_only - ) - - # Remove ignored port -diff --git a/libnmstate/netapplier.py b/libnmstate/netapplier.py -index 3c5759b4..a020f003 100644 ---- a/libnmstate/netapplier.py -+++ b/libnmstate/netapplier.py -@@ -107,8 +107,14 @@ def rollback(*, checkpoint=None): - - - def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk): -+ for plugin in plugins: -+ for iface_name in plugin.get_ignored_kernel_interface_names(): -+ iface = net_state.ifaces.all_kernel_ifaces.get(iface_name) -+ if iface and not iface.is_desired: -+ iface.mark_as_ignored() - for plugin in plugins: - plugin.apply_changes(net_state, save_to_disk) -+ - verified = False - if verify_change: - if _net_state_contains_sriov_interface(net_state): -diff --git a/libnmstate/nispor/plugin.py b/libnmstate/nispor/plugin.py -index dc0ea760..19b21d56 100644 ---- a/libnmstate/nispor/plugin.py -+++ b/libnmstate/nispor/plugin.py -@@ -159,7 +159,11 @@ class NisporPlugin(NmstatePlugin): - np_state = NisporNetState.retrieve() - logging.debug(f"Nispor: current network state {np_state}") - for iface in net_state.ifaces.all_ifaces(): -- if iface.is_desired: -+ if iface.is_ignore: -+ logging.debug( -+ f"Nispor: Interface {iface.name} {iface.type} ignored" -+ ) -+ elif iface.is_desired: - logging.debug( - f"Nispor: desired network state {iface.to_dict()}" - ) -diff --git a/libnmstate/nm/plugin.py b/libnmstate/nm/plugin.py -index 302b4cca..335d93c7 100644 ---- a/libnmstate/nm/plugin.py -+++ b/libnmstate/nm/plugin.py -@@ -36,6 +36,7 @@ from .checkpoint import get_checkpoints - from .common import NM - from .context import NmContext - from .device import get_device_common_info -+from .device import get_iface_type - from .device import list_devices - from .dns import get_running as get_dns_running - from .dns import get_running_config as get_dns_running_config -@@ -268,6 +269,21 @@ class NetworkManagerPlugin(NmstatePlugin): - ) - return NmProfiles(None).generate_config_strings(net_state) - -+ def get_ignored_kernel_interface_names(self): -+ """ -+ Return a list of unmanged kernel interface names. -+ """ -+ ignored_ifaces = set() -+ for nm_dev in list_devices(self.client): -+ if ( -+ nm_dev -+ and nm_dev.get_iface() -+ and not nm_dev.get_managed() -+ and _is_kernel_iface(nm_dev) -+ ): -+ ignored_ifaces.add(nm_dev.get_iface()) -+ return list(ignored_ifaces) -+ - - def _remove_ovs_bridge_unsupported_entries(iface_info): - """ -@@ -283,3 +299,12 @@ def _remove_ovs_bridge_unsupported_entries(iface_info): - - def _nm_utils_decode_version(): - return f"{NM.MAJOR_VERSION}.{NM.MINOR_VERSION}.{NM.MICRO_VERSION}" -+ -+ -+def _is_kernel_iface(nm_dev): -+ iface_type = get_iface_type(nm_dev) -+ return iface_type != InterfaceType.UNKNOWN and iface_type not in ( -+ InterfaceType.OVS_BRIDGE, -+ InterfaceType.OVS_INTERFACE, -+ InterfaceType.OVS_PORT, -+ ) -diff --git a/libnmstate/plugin.py b/libnmstate/plugin.py -index ef3874ff..e1d9ad58 100644 ---- a/libnmstate/plugin.py -+++ b/libnmstate/plugin.py -@@ -128,3 +128,10 @@ class NmstatePlugin(metaclass=ABCMeta): - persistently. - """ - return [] -+ -+ def get_ignored_kernel_interface_names(self): -+ """ -+ Return a list of kernel interface names which should be ignored -+ during verification stage. -+ """ -+ return [] --- -2.29.2 - diff --git a/SOURCES/BZ_1935710-nm-Don-t-touch-unmanaged-interface-unless-desired.patch b/SOURCES/BZ_1935710-nm-Don-t-touch-unmanaged-interface-unless-desired.patch new file mode 100644 index 0000000..ea46af7 --- /dev/null +++ b/SOURCES/BZ_1935710-nm-Don-t-touch-unmanaged-interface-unless-desired.patch @@ -0,0 +1,223 @@ +From ccdcd8f86544a6364109a0c0142d05a5afacf64e Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Tue, 2 Mar 2021 15:31:20 +0800 +Subject: [PATCH] nm: Don't touch unmanaged interface unless desired + +We should ignore NetworkManager unmanaged interface when applying and +verifying unless certain interface listed in desired state explicitly. + +Introduced new plugin interface +`NmstatePlugin.get_ignored_kernel_interface_names()` where plugin may +include a list of interface names which should be ignored during +verification stage. + +Integration test case added to simulate CNV usage on partial editing +a linux bridge holding NM unmanaged interface. + +Signed-off-by: Gris Ge +--- + libnmstate/ifaces/base_iface.py | 3 ++ + libnmstate/ifaces/ifaces.py | 26 ++++++++-------- + libnmstate/netapplier.py | 6 ++++ + libnmstate/nispor/plugin.py | 6 +++- + libnmstate/nm/plugin.py | 25 ++++++++++++++++ + libnmstate/plugin.py | 7 +++++ + tests/integration/linux_bridge_test.py | 8 +---- + tests/integration/nm/linux_bridge_test.py | 36 ++++++++++++++++++++++- + 8 files changed, 95 insertions(+), 22 deletions(-) + +diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py +index 227c1d20..e3f2a1ca 100644 +--- a/libnmstate/ifaces/base_iface.py ++++ b/libnmstate/ifaces/base_iface.py +@@ -322,6 +322,9 @@ class BaseIface: + def mark_as_up(self): + self.raw[Interface.STATE] = InterfaceState.UP + ++ def mark_as_ignored(self): ++ self.raw[Interface.STATE] = InterfaceState.IGNORE ++ + @property + def is_controller(self): + return False +diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py +index 6c94a986..efa24aa3 100644 +--- a/libnmstate/ifaces/ifaces.py ++++ b/libnmstate/ifaces/ifaces.py +@@ -95,7 +95,6 @@ class Ifaces: + self._kernel_ifaces = {} + self._user_space_ifaces = _UserSpaceIfaces() + self._cur_user_space_ifaces = _UserSpaceIfaces() +- self._ignored_ifaces = set() + if cur_iface_infos: + for iface_info in cur_iface_infos: + cur_iface = _to_specific_iface_obj(iface_info, save_to_disk) +@@ -143,10 +142,6 @@ class Ifaces: + ): + # Ignore interface with unknown type + continue +- if iface.is_ignore: +- self._ignored_ifaces.add( +- (iface.name, iface.type, iface.is_user_space_only) +- ) + if cur_iface: + iface.merge(cur_iface) + iface.mark_as_desired() +@@ -169,6 +164,10 @@ class Ifaces: + + self._pre_edit_validation_and_cleanup() + ++ @property ++ def _ignored_ifaces(self): ++ return [iface for iface in self.all_ifaces() if iface.is_ignore] ++ + def _apply_copy_mac_from(self): + for iface in self.all_kernel_ifaces.values(): + if iface.type not in ( +@@ -284,7 +283,7 @@ class Ifaces: + if not defiend in desire state + """ + for iface in self.all_ifaces(): +- if iface.is_up and iface.is_controller: ++ if iface.is_desired and iface.is_up and iface.is_controller: + for port_name in iface.port: + port_iface = self._kernel_ifaces[port_name] + if not port_iface.is_desired and not port_iface.is_up: +@@ -550,13 +549,14 @@ class Ifaces: + return None + + def _remove_iface(self, iface_name, iface_type): +- cur_iface = self._cur_kernel_ifaces.get(iface_name, iface_type) ++ cur_iface = self._user_space_ifaces.get(iface_name, iface_type) + if cur_iface: + self._user_space_ifaces.remove(cur_iface) + else: + cur_iface = self._kernel_ifaces.get(iface_name) + if ( +- iface_type ++ cur_iface ++ and iface_type + and iface_type != InterfaceType.UNKNOWN + and iface_type == cur_iface.type + ): +@@ -813,14 +813,14 @@ class Ifaces: + port_controller_map[port_name] = iface.name + + def _remove_ignore_interfaces(self, ignored_ifaces): +- for iface_name, iface_type, _ in ignored_ifaces: +- self._remove_iface(iface_name, iface_type) ++ for iface in ignored_ifaces: ++ self._remove_iface(iface.name, iface.type) + + # Only kernel interface can be used as port + ignored_kernel_iface_names = set( +- iface_name +- for iface_name, _, is_user_space_only in ignored_ifaces +- if not is_user_space_only ++ iface.name ++ for iface in ignored_ifaces ++ if not iface.is_user_space_only + ) + + # Remove ignored port +diff --git a/libnmstate/netapplier.py b/libnmstate/netapplier.py +index 3c5759b4..a020f003 100644 +--- a/libnmstate/netapplier.py ++++ b/libnmstate/netapplier.py +@@ -107,8 +107,14 @@ def rollback(*, checkpoint=None): + + + def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk): ++ for plugin in plugins: ++ for iface_name in plugin.get_ignored_kernel_interface_names(): ++ iface = net_state.ifaces.all_kernel_ifaces.get(iface_name) ++ if iface and not iface.is_desired: ++ iface.mark_as_ignored() + for plugin in plugins: + plugin.apply_changes(net_state, save_to_disk) ++ + verified = False + if verify_change: + if _net_state_contains_sriov_interface(net_state): +diff --git a/libnmstate/nispor/plugin.py b/libnmstate/nispor/plugin.py +index dc0ea760..19b21d56 100644 +--- a/libnmstate/nispor/plugin.py ++++ b/libnmstate/nispor/plugin.py +@@ -159,7 +159,11 @@ class NisporPlugin(NmstatePlugin): + np_state = NisporNetState.retrieve() + logging.debug(f"Nispor: current network state {np_state}") + for iface in net_state.ifaces.all_ifaces(): +- if iface.is_desired: ++ if iface.is_ignore: ++ logging.debug( ++ f"Nispor: Interface {iface.name} {iface.type} ignored" ++ ) ++ elif iface.is_desired: + logging.debug( + f"Nispor: desired network state {iface.to_dict()}" + ) +diff --git a/libnmstate/nm/plugin.py b/libnmstate/nm/plugin.py +index 302b4cca..335d93c7 100644 +--- a/libnmstate/nm/plugin.py ++++ b/libnmstate/nm/plugin.py +@@ -36,6 +36,7 @@ from .checkpoint import get_checkpoints + from .common import NM + from .context import NmContext + from .device import get_device_common_info ++from .device import get_iface_type + from .device import list_devices + from .dns import get_running as get_dns_running + from .dns import get_running_config as get_dns_running_config +@@ -268,6 +269,21 @@ class NetworkManagerPlugin(NmstatePlugin): + ) + return NmProfiles(None).generate_config_strings(net_state) + ++ def get_ignored_kernel_interface_names(self): ++ """ ++ Return a list of unmanged kernel interface names. ++ """ ++ ignored_ifaces = set() ++ for nm_dev in list_devices(self.client): ++ if ( ++ nm_dev ++ and nm_dev.get_iface() ++ and not nm_dev.get_managed() ++ and _is_kernel_iface(nm_dev) ++ ): ++ ignored_ifaces.add(nm_dev.get_iface()) ++ return list(ignored_ifaces) ++ + + def _remove_ovs_bridge_unsupported_entries(iface_info): + """ +@@ -283,3 +299,12 @@ def _remove_ovs_bridge_unsupported_entries(iface_info): + + def _nm_utils_decode_version(): + return f"{NM.MAJOR_VERSION}.{NM.MINOR_VERSION}.{NM.MICRO_VERSION}" ++ ++ ++def _is_kernel_iface(nm_dev): ++ iface_type = get_iface_type(nm_dev) ++ return iface_type != InterfaceType.UNKNOWN and iface_type not in ( ++ InterfaceType.OVS_BRIDGE, ++ InterfaceType.OVS_INTERFACE, ++ InterfaceType.OVS_PORT, ++ ) +diff --git a/libnmstate/plugin.py b/libnmstate/plugin.py +index ef3874ff..e1d9ad58 100644 +--- a/libnmstate/plugin.py ++++ b/libnmstate/plugin.py +@@ -128,3 +128,10 @@ class NmstatePlugin(metaclass=ABCMeta): + persistently. + """ + return [] ++ ++ def get_ignored_kernel_interface_names(self): ++ """ ++ Return a list of kernel interface names which should be ignored ++ during verification stage. ++ """ ++ return [] +-- +2.29.2 + diff --git a/SPECS/nmstate.spec b/SPECS/nmstate.spec index 06262d2..30100c0 100644 --- a/SPECS/nmstate.spec +++ b/SPECS/nmstate.spec @@ -4,7 +4,7 @@ Name: nmstate Version: 1.0.2 -Release: 5%{?dist} +Release: 6%{?dist} Summary: Declarative network manager API License: LGPLv2+ URL: https://github.com/%{srcname}/%{srcname} @@ -13,7 +13,7 @@ Source1: %{url}/releases/download/v%{version}/%{srcname}-%{version}.tar.g Source2: https://www.nmstate.io/nmstate.gpg Patch1: BZ_1931751-nmstate-fix-return-code.patch Patch2: BZ_1931355-SRIOV-wait-VF-mount-decrease.patch -Patch3: BZ_1932247-nm-Don-t-touch-unmanaged-interface-unless-desired.patch +Patch3: BZ_1935710-nm-Don-t-touch-unmanaged-interface-unless-desired.patch BuildArch: noarch BuildRequires: python3-devel BuildRequires: python3-setuptools @@ -86,8 +86,11 @@ gpgv2 --keyring ./gpgkey-mantainers.gpg %{SOURCE1} %{SOURCE0} %{python3_sitelib}/%{libname}/plugins/__pycache__/nmstate_plugin_ovsdb* %changelog -* Wed Mar 03 2021 Fernando Fernandez Mancera - 1.0.2-5 -- New patch for fixing unmanaged interfaces being managed. RHBZ#1932247 +* Fri Mar 26 2021 Fernando Fernandez Mancera - 1.0.2-6 +- Rebuild for RHEL 8.5. RHBZ#1935710 + +* Fri Mar 26 2021 Fernando Fernandez Mancera - 1.0.2-5 +- New patch for fixing unmanaged interfaces being managed. RHBZ#1935710 * Tue Feb 23 2021 Gris Ge - 1.0.2-4 - New patch for SRIOV decrease VF amount. RHBZ#1931355