From 8c0f309116d9e154d2607d1331c5eced694c62f3 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 18 May 2021 02:55:08 -0400 Subject: [PATCH] import nmstate-1.0.2-5.el8 --- .gitignore | 2 +- .nmstate.metadata | 2 +- SOURCES/BZ_1858758-fix_ovs_bond.patch | 40 -- .../BZ_1858762-hide_ovs_patch_port_mtu.patch | 105 ----- ...Z_1859844-fix_converting_memory_only.patch | 59 --- ...63-handle-external-managed-interface.patch | 65 --- SOURCES/BZ_1861668_ignore_unknown_iface.patch | 200 --------- .../BZ_1862025-remove_existing_profiles.patch | 68 --- ...BZ_1866269-preserve_nm_uuid_in_ovsdb.patch | 120 ----- .../BZ_1869345_ovsdb_remove_all_ports.patch | 44 -- ...49-Allow-duplicate-iface-name-in-ovs.patch | 111 ----- ...re-ad_actor_system-00-00-00-00-00-00.patch | 49 -- ...ar_routing_rules-when-creating-the-s.patch | 33 -- ...do_not_check_ovs_daemon_when_showing.patch | 103 ----- ...9-do-not-remove-unmanaged-ovs-bridge.patch | 38 -- ...cation-retry-to-wait-VF-been-created.patch | 185 -------- ...BZ_1910193-support-multiple-gateways.patch | 92 ---- ..._1916073_better-handling-for-timeout.patch | 419 ------------------ ...16073_retry_on_failure_when_activate.patch | 58 --- ...18712_use_uuid_for_vlan_vxlan_parent.patch | 214 --------- ...not-create-VF-profiles-automatically.patch | 82 ---- ...VF-interface-when-total-vfs-decrease.patch | 112 ----- ...1931355-SRIOV-wait-VF-mount-decrease.patch | 166 +++++++ .../BZ_1931751-nmstate-fix-return-code.patch | 29 ++ ...erification-if-total_vfs-does-not-ma.patch | 79 ---- ...e-the-verification-timeout-if-SR-IOV.patch | 102 ----- ...ridge-do-not-bring-up-existing-ports.patch | 38 -- ...h-unmanaged-interface-unless-desired.patch | 223 ++++++++++ ...-ignore-not-desired-unmanaged-ifaces.patch | 77 ---- ...New-property-Interface.COPY_MAC_FROM.patch | 146 ------ SOURCES/nmstate-0.3.4.tar.gz.asc | 16 - SOURCES/nmstate-1.0.2.tar.gz.asc | 16 + SPECS/nmstate.spec | 105 ++--- 33 files changed, 481 insertions(+), 2717 deletions(-) delete mode 100644 SOURCES/BZ_1858758-fix_ovs_bond.patch delete mode 100644 SOURCES/BZ_1858762-hide_ovs_patch_port_mtu.patch delete mode 100644 SOURCES/BZ_1859844-fix_converting_memory_only.patch delete mode 100644 SOURCES/BZ_1861263-handle-external-managed-interface.patch delete mode 100644 SOURCES/BZ_1861668_ignore_unknown_iface.patch delete mode 100644 SOURCES/BZ_1862025-remove_existing_profiles.patch delete mode 100644 SOURCES/BZ_1866269-preserve_nm_uuid_in_ovsdb.patch delete mode 100644 SOURCES/BZ_1869345_ovsdb_remove_all_ports.patch delete mode 100644 SOURCES/BZ_1887349-Allow-duplicate-iface-name-in-ovs.patch delete mode 100644 SOURCES/BZ_1890497-nm-bond-Ignore-ad_actor_system-00-00-00-00-00-00.patch delete mode 100644 SOURCES/BZ_1890497-nm.ipv6-call-clear_routing_rules-when-creating-the-s.patch delete mode 100644 SOURCES/BZ_1901571_do_not_check_ovs_daemon_when_showing.patch delete mode 100644 SOURCES/BZ_1904889-do-not-remove-unmanaged-ovs-bridge.patch delete mode 100644 SOURCES/BZ_1908724-sriov-use-verification-retry-to-wait-VF-been-created.patch delete mode 100644 SOURCES/BZ_1910193-support-multiple-gateways.patch delete mode 100644 SOURCES/BZ_1916073_better-handling-for-timeout.patch delete mode 100644 SOURCES/BZ_1916073_retry_on_failure_when_activate.patch delete mode 100644 SOURCES/BZ_1918712_use_uuid_for_vlan_vxlan_parent.patch delete mode 100644 SOURCES/BZ_1931290-SRIOV-Do-not-create-VF-profiles-automatically.patch delete mode 100644 SOURCES/BZ_1931290-SRIOV-Remove-VF-interface-when-total-vfs-decrease.patch create mode 100644 SOURCES/BZ_1931355-SRIOV-wait-VF-mount-decrease.patch create mode 100644 SOURCES/BZ_1931751-nmstate-fix-return-code.patch delete mode 100644 SOURCES/BZ_1931784-SR-IOV-fail-on-verification-if-total_vfs-does-not-ma.patch delete mode 100644 SOURCES/BZ_1931784-SR-IOV-increase-the-verification-timeout-if-SR-IOV.patch delete mode 100644 SOURCES/BZ_1932247-bridge-do-not-bring-up-existing-ports.patch create mode 100644 SOURCES/BZ_1932247-nm-Don-t-touch-unmanaged-interface-unless-desired.patch delete mode 100644 SOURCES/BZ_1932247-nm.applier-ignore-not-desired-unmanaged-ifaces.patch delete mode 100644 SOURCES/BZ_1933538-bridge-bond-New-property-Interface.COPY_MAC_FROM.patch delete mode 100644 SOURCES/nmstate-0.3.4.tar.gz.asc create mode 100644 SOURCES/nmstate-1.0.2.tar.gz.asc diff --git a/.gitignore b/.gitignore index 4e6d7d9..18b3d9b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -SOURCES/nmstate-0.3.4.tar.gz +SOURCES/nmstate-1.0.2.tar.gz SOURCES/nmstate.gpg diff --git a/.nmstate.metadata b/.nmstate.metadata index 3f697a6..a6d3e02 100644 --- a/.nmstate.metadata +++ b/.nmstate.metadata @@ -1,2 +1,2 @@ -d732a1ccb1dfc54741a9d602179c809c3223af3a SOURCES/nmstate-0.3.4.tar.gz +eeda8a0238732e5dc37e2217ed6e316f76c93145 SOURCES/nmstate-1.0.2.tar.gz b5f872551d434e2c62b30d70471efaeede83ab44 SOURCES/nmstate.gpg diff --git a/SOURCES/BZ_1858758-fix_ovs_bond.patch b/SOURCES/BZ_1858758-fix_ovs_bond.patch deleted file mode 100644 index d71cfcd..0000000 --- a/SOURCES/BZ_1858758-fix_ovs_bond.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 862e669fcfe02b49c0e24af210d6466197962b97 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Mon, 3 Aug 2020 11:34:44 +0800 -Subject: [PATCH] ovs: Fix bug when adding bond to existing bridge - -When adding OVS bond/link aggregation interface to existing OVS bridge, -nmstate will fail with error: - - > self._ifaces[slave_name].mark_as_changed() - E KeyError: 'bond1' - -This is because ovs bond interface does not require a interface entry in -desire state. - -Fixed by check before adding dict. - -Integration test case added. - -Signed-off-by: Gris Ge ---- - libnmstate/ifaces/ifaces.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py -index a400712..1c2ffd5 100644 ---- a/libnmstate/ifaces/ifaces.py -+++ b/libnmstate/ifaces/ifaces.py -@@ -217,7 +217,8 @@ class Ifaces: - self._ifaces[iface_name].mark_as_changed() - if cur_iface: - for slave_name in iface.config_changed_slaves(cur_iface): -- self._ifaces[slave_name].mark_as_changed() -+ if slave_name in self._ifaces: -+ self._ifaces[slave_name].mark_as_changed() - - def _match_child_iface_state_with_parent(self): - """ --- -2.28.0 - diff --git a/SOURCES/BZ_1858762-hide_ovs_patch_port_mtu.patch b/SOURCES/BZ_1858762-hide_ovs_patch_port_mtu.patch deleted file mode 100644 index 3e5bea9..0000000 --- a/SOURCES/BZ_1858762-hide_ovs_patch_port_mtu.patch +++ /dev/null @@ -1,105 +0,0 @@ -From bc2f8445d493f8a5a4ff1ceead13d2b3ac5325cc Mon Sep 17 00:00:00 2001 -From: Fernando Fernandez Mancera -Date: Sun, 26 Jul 2020 00:46:16 +0200 -Subject: [PATCH 1/2] nm.wired: do not report MTU if it is 0 - -If an interface contains an MTU with value 0, Nmstate should not report -it because it is an special interface like OVS patch port interfaces. - -Added a test case for this. - -Signed-off-by: Fernando Fernandez Mancera ---- - libnmstate/nm/wired.py | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/libnmstate/nm/wired.py b/libnmstate/nm/wired.py -index 27d4318..64662ac 100644 ---- a/libnmstate/nm/wired.py -+++ b/libnmstate/nm/wired.py -@@ -124,7 +124,9 @@ def get_info(device): - - iface = device.get_iface() - try: -- info[Interface.MTU] = int(device.get_mtu()) -+ mtu = int(device.get_mtu()) -+ if mtu: -+ info[Interface.MTU] = mtu - except AttributeError: - pass - --- -2.27.0 - - -From 03aea7d7debfca0f01b60e9f406c9acdf3de3775 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Mon, 27 Jul 2020 20:51:53 +0800 -Subject: [PATCH 2/2] nm ovs: Raise NmstateNotSupportedError for - save_to_disk=False - -Due to limitation of NetworkManager 1.26, nmstate cannot support -`save_to_disk=False`(ask, memory only) state for OVS interfaces. - -Raise NmstateNotSupportedError if NetworkManager version is older than -1.28 and has OVS interface in desire state with `save_to_disk=False`. - -Integration test case included. - -Signed-off-by: Gris Ge -Signed-off-by: Fernando Fernandez Mancera ---- - libnmstate/nm/applier.py | 23 +++++++++++++++++++++++ - 1 file changed, 23 insertions(+) - -diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py -index 4e20af5..a91cee5 100644 ---- a/libnmstate/nm/applier.py -+++ b/libnmstate/nm/applier.py -@@ -17,9 +17,11 @@ - # along with this program. If not, see . - # - -+from distutils.version import StrictVersion - import logging - import itertools - -+from libnmstate.error import NmstateNotSupportedError - from libnmstate.error import NmstateValueError - from libnmstate.schema import Interface - from libnmstate.schema import InterfaceState -@@ -65,6 +67,17 @@ MASTER_IFACE_TYPES = ( - def apply_changes(context, net_state, save_to_disk): - con_profiles = [] - -+ if ( -+ not save_to_disk -+ and _has_ovs_interface_desired_or_changed(net_state) -+ and StrictVersion(context.client.get_version()) -+ < StrictVersion("1.28.0") -+ ): -+ raise NmstateNotSupportedError( -+ f"NetworkManager version {context.client.get_version()} does not " -+ f"support 'save_to_disk=False' against OpenvSwitch interface" -+ ) -+ - _preapply_dns_fix(context, net_state) - - ifaces_desired_state = net_state.ifaces.state_to_edit -@@ -602,3 +615,13 @@ def _preapply_dns_fix(context, net_state): - for iface in net_state.ifaces.values(): - if iface.is_changed or iface.is_desired: - iface.remove_dns_metadata() -+ -+ -+def _has_ovs_interface_desired_or_changed(net_state): -+ for iface in net_state.ifaces.values(): -+ if iface.type in ( -+ InterfaceType.OVS_BRIDGE, -+ InterfaceType.OVS_INTERFACE, -+ InterfaceType.OVS_PORT, -+ ) and (iface.is_desired or iface.is_changed): -+ return True --- -2.27.0 - diff --git a/SOURCES/BZ_1859844-fix_converting_memory_only.patch b/SOURCES/BZ_1859844-fix_converting_memory_only.patch deleted file mode 100644 index ef80e65..0000000 --- a/SOURCES/BZ_1859844-fix_converting_memory_only.patch +++ /dev/null @@ -1,59 +0,0 @@ -From fc7e6b2329409b95ab1726b7b65f14c284bf67ab Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Mon, 3 Aug 2020 12:07:56 +0800 -Subject: [PATCH] nm: Fix converting memory-only profile to persistent - -When converting memory-only profile to persistent using simple desire -state with `state: up` only, the memory only profile will not be -converted to persistent. - -This is caused by `nm/applier.py` skip profile creation if desire state -is only `state: up`. - -The fix is checking whether current profile's persistent state is equal -to desired. - -Integration test case added. - -Signed-off-by: Gris Ge ---- - libnmstate/nm/applier.py | 1 + - libnmstate/nm/connection.py | 10 ++++++++++ - 2 files changed, 11 insertions(+) - -diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py -index 4d40862..26a057f 100644 ---- a/libnmstate/nm/applier.py -+++ b/libnmstate/nm/applier.py -@@ -125,6 +125,7 @@ def apply_changes(context, net_state, save_to_disk): - and cur_con_profile - and cur_con_profile.profile - and not net_state.ifaces[ifname].is_changed -+ and cur_con_profile.is_memory_only != save_to_disk - ): - # Don't create new profile if original desire does not ask - # anything besides state:up and not been marked as changed. -diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py -index 5804f13..1f6c734 100644 ---- a/libnmstate/nm/connection.py -+++ b/libnmstate/nm/connection.py -@@ -162,6 +162,16 @@ class ConnectionProfile: - assert self._con_profile is None - self._con_profile = con_profile - -+ @property -+ def is_memory_only(self): -+ if self._con_profile: -+ profile_flags = self._con_profile.get_flags() -+ return ( -+ NM.SettingsConnectionFlags.UNSAVED & profile_flags -+ or NM.SettingsConnectionFlags.VOLATILE & profile_flags -+ ) -+ return False -+ - @property - def devname(self): - if self._con_profile: --- -2.28.0 - diff --git a/SOURCES/BZ_1861263-handle-external-managed-interface.patch b/SOURCES/BZ_1861263-handle-external-managed-interface.patch deleted file mode 100644 index dc59dc4..0000000 --- a/SOURCES/BZ_1861263-handle-external-managed-interface.patch +++ /dev/null @@ -1,65 +0,0 @@ -From ea7f304cc1ad32c3f2c25b49bf6b2663f348496a Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Tue, 28 Jul 2020 15:59:11 +0800 -Subject: [PATCH] nm: Mark external subordinate as changed - -When user create bond with subordinate interfaces using non-NM -tools(iproute), the NetworkManager will mark the subordinates as -managed externally. - -When the desire state only contains the main interface, nmstate -noticing the slave list is unchanged, so only activate the main -interface, then NM remove the subordinate from their main interface. - -To workaround that, mark subordinate interfaces as changed when they are -managed by NM as externally. - -Integration test case included. - -Signed-off-by: Gris Ge ---- - libnmstate/nm/applier.py | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py -index a91cee5..68d11dc 100644 ---- a/libnmstate/nm/applier.py -+++ b/libnmstate/nm/applier.py -@@ -79,6 +79,7 @@ def apply_changes(context, net_state, save_to_disk): - ) - - _preapply_dns_fix(context, net_state) -+ _mark_nm_external_subordinate_changed(context, net_state) - - ifaces_desired_state = net_state.ifaces.state_to_edit - ifaces_desired_state.extend( -@@ -625,3 +626,26 @@ def _has_ovs_interface_desired_or_changed(net_state): - InterfaceType.OVS_PORT, - ) and (iface.is_desired or iface.is_changed): - return True -+ -+ -+def _mark_nm_external_subordinate_changed(context, net_state): -+ """ -+ When certain main interface contains subordinates is marked as -+ connected(externally), it means its profile is memory only and will lost -+ on next deactivation. -+ For this case, we should mark the subordinate as changed. -+ that subordinate should be marked as changed for NM to take over. -+ """ -+ for iface in net_state.ifaces.values(): -+ if iface.type in MASTER_IFACE_TYPES: -+ for subordinate in iface.slaves: -+ nmdev = context.get_nm_dev(subordinate) -+ if nmdev: -+ nm_ac = nmdev.get_active_connection() -+ if ( -+ nm_ac -+ and NM.ActivationStateFlags.EXTERNAL -+ & nm_ac.get_state_flags() -+ ): -+ subordinate_iface = net_state.ifaces[subordinate] -+ subordinate_iface.mark_as_changed() --- -2.27.0 - diff --git a/SOURCES/BZ_1861668_ignore_unknown_iface.patch b/SOURCES/BZ_1861668_ignore_unknown_iface.patch deleted file mode 100644 index 665dd7d..0000000 --- a/SOURCES/BZ_1861668_ignore_unknown_iface.patch +++ /dev/null @@ -1,200 +0,0 @@ -From a8590744fbdd4bce9ab340ac49a7add31727b990 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Wed, 29 Jul 2020 17:51:27 +0800 -Subject: [PATCH 1/3] nm applier: Fix external managed interface been marked as - changed - -The net_state passing to `_mark_nm_external_subordinate_changed()` -does not contain unknown type interface, so the -`net_state.ifaces[subordinate]` could trigger KeyError as subordinate -not found. - -Changed it to use `get()` and only perform this changes to -desired/changed interface. - -Signed-off-by: Gris Ge ---- - libnmstate/nm/applier.py | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py -index 68d11dc..d0fb5f3 100644 ---- a/libnmstate/nm/applier.py -+++ b/libnmstate/nm/applier.py -@@ -637,7 +637,7 @@ def _mark_nm_external_subordinate_changed(context, net_state): - that subordinate should be marked as changed for NM to take over. - """ - for iface in net_state.ifaces.values(): -- if iface.type in MASTER_IFACE_TYPES: -+ if iface.is_desired or iface.is_changed and iface.is_master: - for subordinate in iface.slaves: - nmdev = context.get_nm_dev(subordinate) - if nmdev: -@@ -647,5 +647,6 @@ def _mark_nm_external_subordinate_changed(context, net_state): - and NM.ActivationStateFlags.EXTERNAL - & nm_ac.get_state_flags() - ): -- subordinate_iface = net_state.ifaces[subordinate] -- subordinate_iface.mark_as_changed() -+ subordinate_iface = net_state.ifaces.get(subordinate) -+ if subordinate_iface: -+ subordinate_iface.mark_as_changed() --- -2.28.0 - - -From 77a05cfe726efc4a4207d57958a71e1730b6d62a Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Wed, 29 Jul 2020 18:02:52 +0800 -Subject: [PATCH 2/3] nm: Ignore externally managed interface for down/absent - main interface - -When main interface been marked as down or absent, its subordinate -should be also marked as so. NetworkManager plugin should ignore -externally managed subordinate in this case. - -Signed-off-by: Gris Ge ---- - libnmstate/nm/applier.py | 26 +++++++++++--------------- - libnmstate/nm/device.py | 8 ++++++++ - 2 files changed, 19 insertions(+), 15 deletions(-) - -diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py -index d0fb5f3..9cd8f9a 100644 ---- a/libnmstate/nm/applier.py -+++ b/libnmstate/nm/applier.py -@@ -50,6 +50,7 @@ from . import vxlan - from . import wired - from .common import NM - from .dns import get_dns_config_iface_names -+from .device import is_externally_managed - - - MAXIMUM_INTERFACE_LENGTH = 15 -@@ -265,13 +266,14 @@ def _set_ifaces_admin_state(context, ifaces_desired_state, con_profiles): - == InterfaceState.ABSENT - ) - for affected_nmdev in nmdevs: -- devs_to_deactivate[ -- affected_nmdev.get_iface() -- ] = affected_nmdev -- if is_absent: -- devs_to_delete_profile[ -+ if not is_externally_managed(affected_nmdev): -+ devs_to_deactivate[ - affected_nmdev.get_iface() - ] = affected_nmdev -+ if is_absent: -+ devs_to_delete_profile[ -+ affected_nmdev.get_iface() -+ ] = affected_nmdev - if ( - is_absent - and nmdev.is_software() -@@ -640,13 +642,7 @@ def _mark_nm_external_subordinate_changed(context, net_state): - if iface.is_desired or iface.is_changed and iface.is_master: - for subordinate in iface.slaves: - nmdev = context.get_nm_dev(subordinate) -- if nmdev: -- nm_ac = nmdev.get_active_connection() -- if ( -- nm_ac -- and NM.ActivationStateFlags.EXTERNAL -- & nm_ac.get_state_flags() -- ): -- subordinate_iface = net_state.ifaces.get(subordinate) -- if subordinate_iface: -- subordinate_iface.mark_as_changed() -+ if nmdev and is_externally_managed(nmdev): -+ subordinate_iface = net_state.ifaces.get(subordinate) -+ if subordinate_iface: -+ subordinate_iface.mark_as_changed() -diff --git a/libnmstate/nm/device.py b/libnmstate/nm/device.py -index 528f57d..a175b71 100644 ---- a/libnmstate/nm/device.py -+++ b/libnmstate/nm/device.py -@@ -23,6 +23,7 @@ from libnmstate.error import NmstateLibnmError - - from . import active_connection as ac - from . import connection -+from .common import NM - - - def activate(context, dev=None, connection_id=None): -@@ -161,3 +162,10 @@ def get_device_common_info(dev): - "type_name": dev.get_type_description(), - "state": dev.get_state(), - } -+ -+ -+def is_externally_managed(nmdev): -+ nm_ac = nmdev.get_active_connection() -+ return ( -+ nm_ac and NM.ActivationStateFlags.EXTERNAL & nm_ac.get_state_flags() -+ ) --- -2.28.0 - - -From afb51e8421b8749962dd9ee2e31b61548de09a78 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Wed, 29 Jul 2020 18:22:32 +0800 -Subject: [PATCH 3/3] state: Remove unmanaged interface before verifying - -Since we remove unknown type interface before sending to apply, -we should also remove unknown type interface before verifying. - -Signed-off-by: Gris Ge ---- - libnmstate/ifaces/ifaces.py | 9 +++++---- - libnmstate/nm/device.py | 4 +--- - 2 files changed, 6 insertions(+), 7 deletions(-) - -diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py -index 1ff4198..a400712 100644 ---- a/libnmstate/ifaces/ifaces.py -+++ b/libnmstate/ifaces/ifaces.py -@@ -286,16 +286,16 @@ class Ifaces: - def cur_ifaces(self): - return self._cur_ifaces - -- def _remove_unmanaged_slaves(self): -+ def _remove_unknown_interface_type_slaves(self): - """ -- When master containing unmanaged slaves, they should be removed from -- master slave list. -+ When master containing slaves with unknown interface type, they should -+ be removed from master slave list before verifying. - """ - for iface in self._ifaces.values(): - if iface.is_up and iface.is_master and iface.slaves: - for slave_name in iface.slaves: - slave_iface = self._ifaces[slave_name] -- if not slave_iface.is_up: -+ if slave_iface.type == InterfaceType.UNKNOWN: - iface.remove_slave(slave_name) - - def verify(self, cur_iface_infos): -@@ -304,6 +304,7 @@ class Ifaces: - cur_iface_infos=cur_iface_infos, - save_to_disk=self._save_to_disk, - ) -+ cur_ifaces._remove_unknown_interface_type_slaves() - for iface in self._ifaces.values(): - if iface.is_desired: - if iface.is_virtual and iface.original_dict.get( -diff --git a/libnmstate/nm/device.py b/libnmstate/nm/device.py -index a175b71..fdf05bc 100644 ---- a/libnmstate/nm/device.py -+++ b/libnmstate/nm/device.py -@@ -166,6 +166,4 @@ def get_device_common_info(dev): - - def is_externally_managed(nmdev): - nm_ac = nmdev.get_active_connection() -- return ( -- nm_ac and NM.ActivationStateFlags.EXTERNAL & nm_ac.get_state_flags() -- ) -+ return nm_ac and NM.ActivationStateFlags.EXTERNAL & nm_ac.get_state_flags() --- -2.28.0 - diff --git a/SOURCES/BZ_1862025-remove_existing_profiles.patch b/SOURCES/BZ_1862025-remove_existing_profiles.patch deleted file mode 100644 index 2a07082..0000000 --- a/SOURCES/BZ_1862025-remove_existing_profiles.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 3c5337a22273717df6fb51818216816bbff77035 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Thu, 30 Jul 2020 16:54:40 +0800 -Subject: [PATCH] nm profile: Remove inactivate profile of desired interface - -For changed/desired interface, NM should remove all its inactive -profiles so that it could update and activate the same one. - -Integration test case included. - -Signed-off-by: Gris Ge ---- - libnmstate/nm/applier.py | 10 +++++++++- - libnmstate/nm/connection.py | 9 +++++++-- - 2 files changed, 16 insertions(+), 3 deletions(-) - -diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py -index 9cd8f9a..4d40862 100644 ---- a/libnmstate/nm/applier.py -+++ b/libnmstate/nm/applier.py -@@ -105,6 +105,15 @@ def apply_changes(context, net_state, save_to_disk): - cur_con_profile = connection.ConnectionProfile( - context, profile=con_profile - ) -+ -+ if save_to_disk: -+ # TODO: Need handle save_to_disk=False -+ connection.delete_iface_profiles_except( -+ context, -+ ifname, -+ cur_con_profile.profile if cur_con_profile else None, -+ ) -+ - original_desired_iface_state = {} - if net_state.ifaces.get(ifname): - iface = net_state.ifaces[ifname] -@@ -137,7 +146,6 @@ def apply_changes(context, net_state, save_to_disk): - con_profiles.append(new_con_profile) - else: - # Missing connection, attempting to create a new one. -- connection.delete_iface_inactive_connections(context, ifname) - new_con_profile.add(save_to_disk) - con_profiles.append(new_con_profile) - context.wait_all_finish() -diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py -index 02890bc..5804f13 100644 ---- a/libnmstate/nm/connection.py -+++ b/libnmstate/nm/connection.py -@@ -496,9 +496,14 @@ def get_device_active_connection(nm_device): - return active_conn - - --def delete_iface_inactive_connections(context, ifname): -+def delete_iface_profiles_except(context, ifname, excluded_profile): - for con in list_connections_by_ifname(context, ifname): -- con.delete() -+ if ( -+ not excluded_profile -+ or not con.profile -+ or con.profile.get_uuid() != excluded_profile.get_uuid() -+ ): -+ con.delete() - - - def list_connections_by_ifname(context, ifname): --- -2.28.0 - diff --git a/SOURCES/BZ_1866269-preserve_nm_uuid_in_ovsdb.patch b/SOURCES/BZ_1866269-preserve_nm_uuid_in_ovsdb.patch deleted file mode 100644 index 214aa8c..0000000 --- a/SOURCES/BZ_1866269-preserve_nm_uuid_in_ovsdb.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 21e06fd5af76cc1fe65497222a04c1cffa2bc546 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Thu, 6 Aug 2020 13:07:59 +0800 -Subject: [PATCH] ovsdb: Preserve the NM external_ids - -For newly created OVS internal interface with customer external_ids, -the ovsdb plugin will remove the NM external_ids `NM.connection.uuid`. - -The fix is read the current `NM.connection.uuid` before applying -configure and merge it with original desired state. - -Integration test cases added. - -Signed-off-by: Gris Ge ---- - libnmstate/plugins/nmstate_plugin_ovsdb.py | 69 +++++++++++++--------- - 1 file changed, 40 insertions(+), 29 deletions(-) - -diff --git a/libnmstate/plugins/nmstate_plugin_ovsdb.py b/libnmstate/plugins/nmstate_plugin_ovsdb.py -index 83965e1..12ab10d 100644 ---- a/libnmstate/plugins/nmstate_plugin_ovsdb.py -+++ b/libnmstate/plugins/nmstate_plugin_ovsdb.py -@@ -161,7 +161,14 @@ class NmstateOvsdbPlugin(NmstatePlugin): - return ifaces - - def apply_changes(self, net_state, save_to_disk): -+ # State might changed after other plugin invoked apply_changes() - self.refresh_content() -+ cur_iface_to_ext_ids = {} -+ for iface_info in self.get_interfaces(): -+ cur_iface_to_ext_ids[iface_info[Interface.NAME]] = iface_info[ -+ OvsDB.OVS_DB_SUBTREE -+ ][OvsDB.EXTERNAL_IDS] -+ - pending_changes = [] - for iface in net_state.ifaces.values(): - if not iface.is_changed and not iface.is_desired: -@@ -174,7 +181,34 @@ class NmstateOvsdbPlugin(NmstatePlugin): - table_name = "Interface" - else: - continue -- pending_changes.extend(_generate_db_change(table_name, iface)) -+ ids_after_nm_applied = cur_iface_to_ext_ids.get(iface.name, {}) -+ ids_before_nm_applied = ( -+ iface.to_dict() -+ .get(OvsDB.OVS_DB_SUBTREE, {}) -+ .get(OvsDB.EXTERNAL_IDS, {}) -+ ) -+ original_desire_ids = iface.original_dict.get( -+ OvsDB.OVS_DB_SUBTREE, {} -+ ).get(OvsDB.EXTERNAL_IDS) -+ -+ desire_ids = [] -+ -+ if original_desire_ids is None: -+ desire_ids = ids_before_nm_applied -+ else: -+ desire_ids = original_desire_ids -+ -+ # should include external_id created by NetworkManager. -+ if NM_EXTERNAL_ID in ids_after_nm_applied: -+ desire_ids[NM_EXTERNAL_ID] = ids_after_nm_applied[ -+ NM_EXTERNAL_ID -+ ] -+ if desire_ids != ids_after_nm_applied: -+ pending_changes.append( -+ _generate_db_change_external_ids( -+ table_name, iface.name, desire_ids -+ ) -+ ) - if pending_changes: - if not save_to_disk: - raise NmstateNotImplementedError( -@@ -242,38 +276,15 @@ class NmstateOvsdbPlugin(NmstatePlugin): - ) - - --def _generate_db_change(table_name, iface_state): -- return _generate_db_change_external_ids(table_name, iface_state) -- -- --def _generate_db_change_external_ids(table_name, iface_state): -- pending_changes = [] -- desire_ids = iface_state.original_dict.get(OvsDB.OVS_DB_SUBTREE, {}).get( -- OvsDB.EXTERNAL_IDS -- ) -+def _generate_db_change_external_ids(table_name, iface_name, desire_ids): - if desire_ids and not isinstance(desire_ids, dict): - raise NmstateValueError("Invalid external_ids, should be dictionary") - -- if desire_ids or desire_ids == {}: -- # should include external_id required by NetworkManager. -- merged_ids = ( -- iface_state.to_dict() -- .get(OvsDB.OVS_DB_SUBTREE, {}) -- .get(OvsDB.EXTERNAL_IDS, {}) -- ) -- if NM_EXTERNAL_ID in merged_ids: -- desire_ids[NM_EXTERNAL_ID] = merged_ids[NM_EXTERNAL_ID] -- -- # Convert all value to string -- for key, value in desire_ids.items(): -- desire_ids[key] = str(value) -+ # Convert all value to string -+ for key, value in desire_ids.items(): -+ desire_ids[key] = str(value) - -- pending_changes.append( -- _Changes( -- table_name, OvsDB.EXTERNAL_IDS, iface_state.name, desire_ids -- ) -- ) -- return pending_changes -+ return _Changes(table_name, OvsDB.EXTERNAL_IDS, iface_name, desire_ids) - - - NMSTATE_PLUGIN = NmstateOvsdbPlugin --- -2.28.0 - diff --git a/SOURCES/BZ_1869345_ovsdb_remove_all_ports.patch b/SOURCES/BZ_1869345_ovsdb_remove_all_ports.patch deleted file mode 100644 index e1a1ac3..0000000 --- a/SOURCES/BZ_1869345_ovsdb_remove_all_ports.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 913b739c8fea8e9b14d3785371c8e4f48723dbd6 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Tue, 18 Aug 2020 17:55:12 +0800 -Subject: [PATCH] ovsdb: Allowing remove all ports from OVS bridge - -When removing all ports from OVS bridge, the OVSDB will have no -information regarding this bridge, which cause OVSDB failed to find -the correct row. - -Silently ignore row not found failure and let verification stage do the -work. - -Signed-off-by: Gris Ge ---- - libnmstate/plugins/nmstate_plugin_ovsdb.py | 8 -------- - 1 file changed, 8 deletions(-) - -diff --git a/libnmstate/plugins/nmstate_plugin_ovsdb.py b/libnmstate/plugins/nmstate_plugin_ovsdb.py -index 12ab10d..f667e8f 100644 ---- a/libnmstate/plugins/nmstate_plugin_ovsdb.py -+++ b/libnmstate/plugins/nmstate_plugin_ovsdb.py -@@ -222,19 +222,11 @@ class NmstateOvsdbPlugin(NmstatePlugin): - def _db_write(self, changes): - changes_index = {change.row_name: change for change in changes} - changed_tables = set(change.table_name for change in changes) -- updated_names = [] - for changed_table in changed_tables: - for row in self._idl.tables[changed_table].rows.values(): - if row.name in changes_index: - change = changes_index[row.name] - setattr(row, change.column_name, change.column_value) -- updated_names.append(change.row_name) -- new_rows = set(changes_index.keys()) - set(updated_names) -- if new_rows: -- raise NmstatePluginError( -- f"BUG: row {new_rows} does not exists in OVS DB " -- "and currently we don't create new row" -- ) - - def _start_transaction(self): - self._transaction = Transaction(self._idl) --- -2.28.0 - diff --git a/SOURCES/BZ_1887349-Allow-duplicate-iface-name-in-ovs.patch b/SOURCES/BZ_1887349-Allow-duplicate-iface-name-in-ovs.patch deleted file mode 100644 index d47e0d8..0000000 --- a/SOURCES/BZ_1887349-Allow-duplicate-iface-name-in-ovs.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 36ee761dd0d671439323077e4f77a89071fdcd9c Mon Sep 17 00:00:00 2001 -From: Edward Haas -Date: Wed, 7 Oct 2020 20:13:12 +0300 -Subject: [PATCH 1/2] nm, bridge, ovs: Collect only existing profiles - -During the reporting flow, connections that are in teardown process -no longer point to a valid profile. Avoid collecting such profiles (in -practice, these are actually `None` objects). - -Signed-off-by: Edward Haas -Signed-off-by: Gris Ge ---- - libnmstate/nm/bridge.py | 6 +++--- - libnmstate/nm/ovs.py | 4 +++- - 2 files changed, 6 insertions(+), 4 deletions(-) - -diff --git a/libnmstate/nm/bridge.py b/libnmstate/nm/bridge.py -index b885f7a..0ca6c2d 100644 ---- a/libnmstate/nm/bridge.py -+++ b/libnmstate/nm/bridge.py -@@ -260,9 +260,9 @@ def _get_slave_profiles_by_name(master_device): - for dev in master_device.get_slaves(): - active_con = connection.get_device_active_connection(dev) - if active_con: -- slaves_profiles_by_name[ -- dev.get_iface() -- ] = active_con.props.connection -+ profile = active_con.props.connection -+ if profile: -+ slaves_profiles_by_name[dev.get_iface()] = profile - return slaves_profiles_by_name - - -diff --git a/libnmstate/nm/ovs.py b/libnmstate/nm/ovs.py -index 2518773..eb373c3 100644 ---- a/libnmstate/nm/ovs.py -+++ b/libnmstate/nm/ovs.py -@@ -279,5 +279,7 @@ def _get_slave_profiles(master_device, devices_info): - if active_con: - master = active_con.props.master - if master and (master.get_iface() == master_device.get_iface()): -- slave_profiles.append(active_con.props.connection) -+ profile = active_con.props.connection -+ if profile: -+ slave_profiles.append(profile) - return slave_profiles --- -2.28.0 - - -From caf638d75e57da8770cd884782475f1c5668fd6d Mon Sep 17 00:00:00 2001 -From: Edward Haas -Date: Wed, 7 Oct 2020 12:26:42 +0300 -Subject: [PATCH 2/2] nm, ovs: Fix report crash when OVS has dup iface names - -In case of an existing OVS deployment which uses an identical name for -the bridge, port and interface, libnmstate.show() exploded. - -It is now possible to report such deployments. - -Signed-off-by: Edward Haas -Signed-off-by: Gris Ge ---- - libnmstate/nm/ovs.py | 24 +++++++++++++++++++++--- - 1 file changed, 21 insertions(+), 3 deletions(-) - -diff --git a/libnmstate/nm/ovs.py b/libnmstate/nm/ovs.py -index eb373c3..d1f26ba 100644 ---- a/libnmstate/nm/ovs.py -+++ b/libnmstate/nm/ovs.py -@@ -140,7 +140,12 @@ def get_port_by_slave(nmdev): - - - def get_ovs_info(context, bridge_device, devices_info): -- port_profiles = _get_slave_profiles(bridge_device, devices_info) -+ ovs_ports_info = ( -+ info -+ for info in devices_info -+ if is_ovs_port_type_id(info[1]["type_id"]) -+ ) -+ port_profiles = _get_slave_profiles(bridge_device, ovs_ports_info) - ports = _get_bridge_ports_info(context, port_profiles, devices_info) - options = _get_bridge_options(context, bridge_device) - -@@ -203,8 +208,21 @@ def _get_bridge_port_info(context, port_profile, devices_info): - vlan_mode = port_setting.props.vlan_mode - - port_name = port_profile.get_interface_name() -- port_device = context.get_nm_dev(port_name) -- port_slave_profiles = _get_slave_profiles(port_device, devices_info) -+ port_device = next( -+ dev -+ for dev, devinfo in devices_info -+ if devinfo["name"] == port_name -+ and is_ovs_port_type_id(devinfo["type_id"]) -+ ) -+ devices_info_excluding_bridges_and_ports = ( -+ info -+ for info in devices_info -+ if not is_ovs_bridge_type_id(info[1]["type_id"]) -+ and not is_ovs_port_type_id(info[1]["type_id"]) -+ ) -+ port_slave_profiles = _get_slave_profiles( -+ port_device, devices_info_excluding_bridges_and_ports -+ ) - port_slave_names = [c.get_interface_name() for c in port_slave_profiles] - - if port_slave_names: --- -2.28.0 - diff --git a/SOURCES/BZ_1890497-nm-bond-Ignore-ad_actor_system-00-00-00-00-00-00.patch b/SOURCES/BZ_1890497-nm-bond-Ignore-ad_actor_system-00-00-00-00-00-00.patch deleted file mode 100644 index 986aab9..0000000 --- a/SOURCES/BZ_1890497-nm-bond-Ignore-ad_actor_system-00-00-00-00-00-00.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 8a7f1758da4cba81d65ba4b9b06bbf4b750a6f87 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Thu, 22 Oct 2020 14:09:27 +0800 -Subject: [PATCH 1/2] nm bond: Ignore ad_actor_system=00:00:00:00:00:00 - -The ad_actor_system=00:00:00:00:00:00 is invalid in kernel as that's the -default value of ad_actor_system. - -NM plugin should not set that value. - -Test case included. - -Signed-off-by: Gris Ge -Signed-off-by: Fernando Fernandez Mancera ---- - libnmstate/nm/bond.py | 9 +++++++++ - tests/integration/nm/bond_test.py | 12 ++++++++++++ - 2 files changed, 21 insertions(+) - -diff --git a/libnmstate/nm/bond.py b/libnmstate/nm/bond.py -index 9ea3648..d196965 100644 ---- a/libnmstate/nm/bond.py -+++ b/libnmstate/nm/bond.py -@@ -38,6 +38,8 @@ NM_SUPPORTED_BOND_OPTIONS = NM.SettingBond.get_valid_options( - - SYSFS_BOND_OPTION_FOLDER_FMT = "/sys/class/net/{ifname}/bonding" - -+BOND_AD_ACTOR_SYSTEM_USE_BOND_MAC = "00:00:00:00:00:00" -+ - - def create_setting(options, wired_setting): - bond_setting = NM.SettingBond.new() -@@ -48,6 +50,13 @@ def create_setting(options, wired_setting): - ): - # When in MAC restricted mode, MAC address should be unset. - wired_setting.props.cloned_mac_address = None -+ if ( -+ option_name == "ad_actor_system" -+ and option_value == BOND_AD_ACTOR_SYSTEM_USE_BOND_MAC -+ ): -+ # The all zero ad_actor_system is the kernel default value -+ # And it is invalid to set as all zero -+ continue - if option_value != SYSFS_EMPTY_VALUE: - success = bond_setting.add_option(option_name, str(option_value)) - if not success: --- -2.25.4 - diff --git a/SOURCES/BZ_1890497-nm.ipv6-call-clear_routing_rules-when-creating-the-s.patch b/SOURCES/BZ_1890497-nm.ipv6-call-clear_routing_rules-when-creating-the-s.patch deleted file mode 100644 index 5c6f4b5..0000000 --- a/SOURCES/BZ_1890497-nm.ipv6-call-clear_routing_rules-when-creating-the-s.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 46104725c121def5d85f492afd91e618c1c7c240 Mon Sep 17 00:00:00 2001 -From: Fernando Fernandez Mancera -Date: Tue, 27 Oct 2020 12:23:18 +0100 -Subject: [PATCH 2/2] nm.ipv6: call clear_routing_rules() when creating the - setting - -In order to remove IPv6 routing rules Nmstate needs to call -clear_routing_rules() on the IPv6 setting as it is done on the IPv4 -setting. - -Added a testcase for this. - -Signed-off-by: Fernando Fernandez Mancera ---- - libnmstate/nm/ipv6.py | 1 + - tests/integration/route_test.py | 15 +++++++++++++++ - 2 files changed, 16 insertions(+) - -diff --git a/libnmstate/nm/ipv6.py b/libnmstate/nm/ipv6.py -index f252578..9777c89 100644 ---- a/libnmstate/nm/ipv6.py -+++ b/libnmstate/nm/ipv6.py -@@ -106,6 +106,7 @@ def create_setting(config, base_con_profile): - setting_ip.props.never_default = False - setting_ip.props.ignore_auto_dns = False - setting_ip.clear_routes() -+ setting_ip.clear_routing_rules() - setting_ip.props.gateway = None - setting_ip.props.route_table = Route.USE_DEFAULT_ROUTE_TABLE - setting_ip.props.route_metric = Route.USE_DEFAULT_METRIC --- -2.25.4 - diff --git a/SOURCES/BZ_1901571_do_not_check_ovs_daemon_when_showing.patch b/SOURCES/BZ_1901571_do_not_check_ovs_daemon_when_showing.patch deleted file mode 100644 index 5a91b83..0000000 --- a/SOURCES/BZ_1901571_do_not_check_ovs_daemon_when_showing.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 2595c75cb8488e855fc5d98bcc944c6c0ad96b54 Mon Sep 17 00:00:00 2001 -From: Quique Llorente -Date: Tue, 24 Nov 2020 12:52:35 +0100 -Subject: [PATCH 1/2] ovs: Ignore ovs-port always - -At containerize nmstate we cannot run "systemctl openvswitch status" so -even with a openvswitch running at host it will appear as non running -but the ovs information will arrive from NM dbus interface. This breaks -nmstatectl show since ovs-port is not part of nmstate and is not -included in the schema. This change just ignore ovs-port even if -openvswitch appear as not running. - -Signed-off-by: Quique Llorente -Signed-off-by: Gris Ge ---- - libnmstate/nm/plugin.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/libnmstate/nm/plugin.py b/libnmstate/nm/plugin.py -index 4032359..6b6217d 100644 ---- a/libnmstate/nm/plugin.py -+++ b/libnmstate/nm/plugin.py -@@ -123,6 +123,8 @@ class NetworkManagerPlugin(NmstatePlugin): - if nm_bond.is_bond_type_id(type_id): - bondinfo = nm_bond.get_bond_info(dev) - iface_info.update(_ifaceinfo_bond(bondinfo)) -+ elif nm_ovs.is_ovs_port_type_id(type_id): -+ continue - elif NmstatePlugin.OVS_CAPABILITY in capabilities: - if nm_ovs.is_ovs_bridge_type_id(type_id): - iface_info["bridge"] = nm_ovs.get_ovs_info( -@@ -133,8 +135,6 @@ class NetworkManagerPlugin(NmstatePlugin): - ) - elif nm_ovs.is_ovs_interface_type_id(type_id): - iface_info.update(nm_ovs.get_interface_info(act_con)) -- elif nm_ovs.is_ovs_port_type_id(type_id): -- continue - - info.append(iface_info) - --- -2.29.2 - - -From 3202bdd08737087160ff96bcf921793ce6b8335c Mon Sep 17 00:00:00 2001 -From: Quique Llorente -Date: Wed, 25 Nov 2020 10:28:43 +0100 -Subject: [PATCH 2/2] ovs: Ignore OVS capabilities at get interfaces - -At containerize nmstate we cannot run "systemctl openvswitch status" so -even with a openvswitch running at host it will appear as non running -but the ovs information will arrive from NM dbus interface. This breaks -nmstatectl show since ovs-port is not part of nmstate and is not -included in the schema. This change removed the whole OVS compatibility check -when processing the interfaces reporting. - -Signed-off-by: Quique Llorente -Signed-off-by: Gris Ge ---- - libnmstate/nm/plugin.py | 18 +++++++----------- - 1 file changed, 7 insertions(+), 11 deletions(-) - -diff --git a/libnmstate/nm/plugin.py b/libnmstate/nm/plugin.py -index 6b6217d..06a5acd 100644 ---- a/libnmstate/nm/plugin.py -+++ b/libnmstate/nm/plugin.py -@@ -97,7 +97,6 @@ class NetworkManagerPlugin(NmstatePlugin): - - def get_interfaces(self): - info = [] -- capabilities = self.capabilities - - devices_info = [ - (dev, nm_device.get_device_common_info(dev)) -@@ -123,18 +122,15 @@ class NetworkManagerPlugin(NmstatePlugin): - if nm_bond.is_bond_type_id(type_id): - bondinfo = nm_bond.get_bond_info(dev) - iface_info.update(_ifaceinfo_bond(bondinfo)) -+ elif nm_ovs.is_ovs_bridge_type_id(type_id): -+ iface_info["bridge"] = nm_ovs.get_ovs_info( -+ self.context, dev, devices_info -+ ) -+ iface_info = _remove_ovs_bridge_unsupported_entries(iface_info) -+ elif nm_ovs.is_ovs_interface_type_id(type_id): -+ iface_info.update(nm_ovs.get_interface_info(act_con)) - elif nm_ovs.is_ovs_port_type_id(type_id): - continue -- elif NmstatePlugin.OVS_CAPABILITY in capabilities: -- if nm_ovs.is_ovs_bridge_type_id(type_id): -- iface_info["bridge"] = nm_ovs.get_ovs_info( -- self.context, dev, devices_info -- ) -- iface_info = _remove_ovs_bridge_unsupported_entries( -- iface_info -- ) -- elif nm_ovs.is_ovs_interface_type_id(type_id): -- iface_info.update(nm_ovs.get_interface_info(act_con)) - - info.append(iface_info) - --- -2.29.2 - diff --git a/SOURCES/BZ_1904889-do-not-remove-unmanaged-ovs-bridge.patch b/SOURCES/BZ_1904889-do-not-remove-unmanaged-ovs-bridge.patch deleted file mode 100644 index e54c13f..0000000 --- a/SOURCES/BZ_1904889-do-not-remove-unmanaged-ovs-bridge.patch +++ /dev/null @@ -1,38 +0,0 @@ -From d7393d40aaedeea5dd8291519cddeecdfdabc849 Mon Sep 17 00:00:00 2001 -From: Fernando Fernandez Mancera -Date: Mon, 7 Dec 2020 00:51:19 +0100 -Subject: [PATCH] ifaces: do not remove unmanaged orphan interfaces - -If there are unmanaged OVS interface present in the network state, NM -may report uncomplete information. Therefore, nmstate could consider -them as orphan and remove it when modifying the network state. - -In order to fix this, nmstate should not consider it orphan and remove -it when it is not on desired state or marked as changed. - -Signed-off-by: Fernando Fernandez Mancera -Signed-off-by: Gris Ge ---- - libnmstate/ifaces/ifaces.py | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py -index 1c2ffd5..703e672 100644 ---- a/libnmstate/ifaces/ifaces.py -+++ b/libnmstate/ifaces/ifaces.py -@@ -242,8 +242,10 @@ class Ifaces: - - def _mark_orphen_as_absent(self): - for iface in self._ifaces.values(): -- if iface.need_parent and ( -- not iface.parent or not self._ifaces.get(iface.parent) -+ if ( -+ iface.need_parent -+ and (not iface.parent or not self._ifaces.get(iface.parent)) -+ and (iface.is_desired or iface.is_changed) - ): - iface.mark_as_changed() - iface.state = InterfaceState.ABSENT --- -2.18.4 - diff --git a/SOURCES/BZ_1908724-sriov-use-verification-retry-to-wait-VF-been-created.patch b/SOURCES/BZ_1908724-sriov-use-verification-retry-to-wait-VF-been-created.patch deleted file mode 100644 index 8427fbd..0000000 --- a/SOURCES/BZ_1908724-sriov-use-verification-retry-to-wait-VF-been-created.patch +++ /dev/null @@ -1,185 +0,0 @@ -From 1d0656c4197f0119d156b0df7b13bffeb5c46861 Mon Sep 17 00:00:00 2001 -From: Gris Ge -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 ---- - 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 - diff --git a/SOURCES/BZ_1910193-support-multiple-gateways.patch b/SOURCES/BZ_1910193-support-multiple-gateways.patch deleted file mode 100644 index b9aa129..0000000 --- a/SOURCES/BZ_1910193-support-multiple-gateways.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 47bd6db50e33aaa3d3d5e3b70d5f3039122b3a5c Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Sat, 5 Sep 2020 00:36:41 +0800 -Subject: [PATCH] nm route: Add support of multiple gateways - -Since NetworkManager 1.22.0, the `NM.SettingIPConfig.props.routes` -support assigning multiple gateway. - -Integration test case updated for this. - -Signed-off-by: Gris Ge ---- - libnmstate/nm/route.py | 30 +++--------------------------- - 1 file changed, 3 insertions(+), 27 deletions(-) - -diff --git a/libnmstate/nm/route.py b/libnmstate/nm/route.py -index 53bcf7c..548b218 100644 ---- a/libnmstate/nm/route.py -+++ b/libnmstate/nm/route.py -@@ -21,7 +21,6 @@ from operator import itemgetter - import socket - - from libnmstate import iplib --from libnmstate.error import NmstateNotImplementedError - from libnmstate.error import NmstateValueError - from libnmstate.nm import active_connection as nm_ac - from libnmstate.schema import Interface -@@ -31,7 +30,6 @@ from libnmstate.schema import RouteRule - from .common import GLib - from .common import NM - --NM_ROUTE_TABLE_ATTRIBUTE = "table" - IPV4_DEFAULT_GATEWAY_DESTINATION = "0.0.0.0/0" - IPV6_DEFAULT_GATEWAY_DESTINATION = "::/0" - -@@ -116,7 +114,7 @@ def get_config(acs_and_ip_profiles): - - - def _get_per_route_table_id(nm_route, default_table_id): -- table = nm_route.get_attribute(NM_ROUTE_TABLE_ATTRIBUTE) -+ table = nm_route.get_attribute(NM.IP_ROUTE_ATTRIBUTE_TABLE) - return int(table.get_uint32()) if table else default_table_id - - -@@ -152,19 +150,7 @@ def _get_default_route_config(gateway, metric, default_table_id, iface_name): - - def add_routes(setting_ip, routes): - for route in routes: -- if route[Route.DESTINATION] in ( -- IPV4_DEFAULT_GATEWAY_DESTINATION, -- IPV6_DEFAULT_GATEWAY_DESTINATION, -- ): -- if setting_ip.get_gateway(): -- raise NmstateNotImplementedError( -- "Only a single default gateway is supported due to a " -- "limitation of NetworkManager: " -- "https://bugzilla.redhat.com/1707396" -- ) -- _add_route_gateway(setting_ip, route) -- else: -- _add_specfic_route(setting_ip, route) -+ _add_specfic_route(setting_ip, route) - - - def _add_specfic_route(setting_ip, route): -@@ -181,22 +167,12 @@ def _add_specfic_route(setting_ip, route): - ) - table_id = route.get(Route.TABLE_ID, Route.USE_DEFAULT_ROUTE_TABLE) - ip_route.set_attribute( -- NM_ROUTE_TABLE_ATTRIBUTE, GLib.Variant.new_uint32(table_id) -+ NM.IP_ROUTE_ATTRIBUTE_TABLE, GLib.Variant.new_uint32(table_id) - ) - # Duplicate route entry will be ignored by libnm. - setting_ip.add_route(ip_route) - - --def _add_route_gateway(setting_ip, route): -- setting_ip.props.gateway = route[Route.NEXT_HOP_ADDRESS] -- setting_ip.props.route_table = route.get( -- Route.TABLE_ID, Route.USE_DEFAULT_ROUTE_TABLE -- ) -- setting_ip.props.route_metric = route.get( -- Route.METRIC, Route.USE_DEFAULT_METRIC -- ) -- -- - def get_static_gateway_iface(family, iface_routes): - """ - Return one interface with gateway for given IP family. --- -2.27.0 - diff --git a/SOURCES/BZ_1916073_better-handling-for-timeout.patch b/SOURCES/BZ_1916073_better-handling-for-timeout.patch deleted file mode 100644 index b47a1d8..0000000 --- a/SOURCES/BZ_1916073_better-handling-for-timeout.patch +++ /dev/null @@ -1,419 +0,0 @@ -From 803ad90f11eb57221e7805e5cba8c309bafe1de8 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Wed, 13 Jan 2021 23:51:31 +0800 -Subject: [PATCH 1/2] nm: Better handling for timeout - -When creating 1000 VLAN along with 1000 bridge using each VLAN, -NetworkManager might trigger two timeout: - - * The callback raises `Gio.IOErrorEnum.TIMED_OUT` error. - * NetworkManager never call callback, nmstate idle check trigger the - timeout. - -To solve above issue: - - * Increase the nmstate idle check timeout to 5 minutes. - - * For actions like add profile and activate profile, we add a - fallback checker which check whether requested action is already - finished using `GLib.timeout_source_new()` - - * When `Gio.IOErrorEnum.TIMED_OUT` happens, ignore the failure and wait - fallback checker. - - * The fallback checker is only started 15 seconds after action started, - so this does not impact small desire state. - -Test results on RHEL 8.3 i7-8665U 2G RAM: - - 10m29.212s to create 1000 VLAN and 1000 bridge over each VLAN. - -Changed the integration test case to test 500 VLANs + 500 bridges. - -Signed-off-by: Gris Ge ---- - libnmstate/nm/connection.py | 67 ++++++++++++++++++++++++++++++++++++- - libnmstate/nm/context.py | 3 +- - 2 files changed, 67 insertions(+), 3 deletions(-) - -diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py -index 1f6c734..374a379 100644 ---- a/libnmstate/nm/connection.py -+++ b/libnmstate/nm/connection.py -@@ -1,5 +1,5 @@ - # --# Copyright (c) 2018-2020 Red Hat, Inc. -+# Copyright (c) 2018-2021 Red Hat, Inc. - # - # This file is part of nmstate - # -@@ -24,11 +24,14 @@ from libnmstate.error import NmstateLibnmError - from libnmstate.error import NmstateInternalError - from libnmstate.error import NmstateValueError - -+from .common import GLib -+from .common import Gio - from .common import NM - from . import ipv4 - from . import ipv6 - - ACTIVATION_TIMEOUT_FOR_BRIDGE = 35 # Bridge STP requires 30 seconds. -+FALLBACK_CHECKER_INTERNAL = 15 - - - class ConnectionProfile: -@@ -40,6 +43,7 @@ class ConnectionProfile: - self._nm_ac = None - self._ac_handlers = set() - self._dev_handlers = set() -+ self._fallback_checker = None - - def create(self, settings): - self.profile = NM.SimpleConnection.new() -@@ -102,6 +106,26 @@ class ConnectionProfile: - self._add_connection2_callback, - user_data, - ) -+ self._fallback_checker = GLib.timeout_source_new( -+ FALLBACK_CHECKER_INTERNAL * 1000 -+ ) -+ self._fallback_checker.set_callback( -+ self._profile_add_fallback_checker_callback, action -+ ) -+ self._fallback_checker.attach(self._ctx.context) -+ -+ def _profile_add_fallback_checker_callback(self, action): -+ for nm_profile in self._ctx.client.get_connections(): -+ if nm_profile.get_uuid() == self.profile.get_uuid(): -+ self._fallback_checker_cleanup() -+ self._ctx.finish_async(action) -+ return GLib.SOURCE_REMOVE -+ return GLib.SOURCE_CONTINUE -+ -+ def _fallback_checker_cleanup(self): -+ if self._fallback_checker: -+ self._fallback_checker.destroy() -+ self._fallback_checker = None - - def delete(self): - if not self.profile: -@@ -152,6 +176,26 @@ class ConnectionProfile: - self._active_connection_callback, - user_data, - ) -+ self._fallback_checker = GLib.timeout_source_new( -+ FALLBACK_CHECKER_INTERNAL * 1000 -+ ) -+ self._fallback_checker.set_callback( -+ self._activation_fallback_checker_callback, action -+ ) -+ self._fallback_checker.attach(self._ctx.context) -+ -+ def _activation_fallback_checker_callback(self, action): -+ if self.devname: -+ self._nm_dev = self._ctx.get_nm_dev(self.devname) -+ if self._nm_dev: -+ self._activation_progress_check(action) -+ return GLib.SOURCE_CONTINUE -+ else: -+ logging.warn( -+ "Failed to get interface name from profile, " -+ "can not perform flalback check on activation" -+ ) -+ return GLib.SOURCE_REMOVE - - @property - def profile(self): -@@ -213,6 +257,18 @@ class ConnectionProfile: - - try: - nm_act_con = src_object.activate_connection_finish(result) -+ except GLib.Error as e: -+ if e.matches(Gio.io_error_quark(), Gio.IOErrorEnum.TIMED_OUT): -+ logging.debug( -+ f"{action} timeout on activation, " -+ "using fallback method to wait activation" -+ ) -+ return -+ else: -+ self._ctx.fail( -+ NmstateLibnmError(f"{action} failed: error={e}") -+ ) -+ return - except Exception as e: - self._ctx.fail(NmstateLibnmError(f"{action} failed: error={e}")) - return -@@ -366,6 +422,7 @@ class ConnectionProfile: - def _activation_clean_up(self): - self._remove_ac_handlers() - self._remove_dev_handlers() -+ self._fallback_checker_cleanup() - - def _is_activating(self): - if not self._nm_ac or not self._nm_dev: -@@ -396,6 +453,13 @@ class ConnectionProfile: - action = user_data - try: - profile = src_object.add_connection2_finish(result)[0] -+ except GLib.Error as e: -+ if e.matches(Gio.io_error_quark(), Gio.IOErrorEnum.TIMED_OUT): -+ logging.debug( -+ f"{action} timeout, using fallback method to " -+ "wait profile creation" -+ ) -+ return - except Exception as e: - self._ctx.fail( - NmstateLibnmError(f"{action} failed with error: {e}") -@@ -410,6 +474,7 @@ class ConnectionProfile: - ) - ) - else: -+ self._fallback_checker_cleanup() - self._ctx.finish_async(action) - - def _update2_callback(self, src_object, result, user_data): -diff --git a/libnmstate/nm/context.py b/libnmstate/nm/context.py -index 373ffe8..bc5c41c 100644 ---- a/libnmstate/nm/context.py -+++ b/libnmstate/nm/context.py -@@ -31,8 +31,7 @@ from .common import Gio - # last finish async action. - IDLE_CHECK_INTERNAL = 5 - --# libnm dbus connection has reply timeout 25 seconds. --IDLE_TIMEOUT = 25 -+IDLE_TIMEOUT = 60 * 5 # 5 minutes - - # NetworkManage is using dbus in libnm while the dbus has limitation on - # maximum number of pending replies per connection.(RHEL/CentOS 8 is 1024) --- -2.27.0 - - -From ac82d18f96aa2313583efa1477be441291e2957c Mon Sep 17 00:00:00 2001 -From: Fernando Fernandez Mancera -Date: Sun, 17 Jan 2021 11:18:10 +0800 -Subject: [PATCH 2/2] nm: Use fallback checker on profile deactivation and - delete - -When NM is under heave loads, NM might raise timeout error when -try to deactivate or delete a profile, to solve that this patch -introduce the same method in 2407f98 -to have a fallback checker on whether profile is deactivated/deleted -every 15 seconds. - -No test case required as current `test_lot_of_vlans_with_bridges` test -case has `state: absent` which is good enough for testing this patch. - -Signed-off-by: Fernando Fernandez Mancera -Signed-off-by: Gris Ge ---- - libnmstate/nm/active_connection.py | 61 ++++++++++++++++++++++++------ - libnmstate/nm/connection.py | 30 +++++++++++++++ - 2 files changed, 80 insertions(+), 11 deletions(-) - -diff --git a/libnmstate/nm/active_connection.py b/libnmstate/nm/active_connection.py -index 062c78a..b235e8b 100644 ---- a/libnmstate/nm/active_connection.py -+++ b/libnmstate/nm/active_connection.py -@@ -21,12 +21,14 @@ import logging - - from libnmstate.error import NmstateLibnmError - -+from .common import Gio - from .common import GLib - from .common import GObject - from .common import NM - - - NM_AC_STATE_CHANGED_SIGNAL = "state-changed" -+FALLBACK_CHECKER_INTERNAL = 15 - - - class ActivationError(Exception): -@@ -37,6 +39,8 @@ class ActiveConnection: - def __init__(self, context=None, nm_ac_con=None): - self._ctx = context - self._act_con = nm_ac_con -+ self._signal_handler = None -+ self._fallback_checker = None - - nmdevs = None - if nm_ac_con: -@@ -75,19 +79,35 @@ class ActiveConnection: - - action = f"Deactivate profile: {self.devname}" - self._ctx.register_async(action) -- handler_id = act_connection.connect( -+ self._signal_handler = act_connection.connect( - NM_AC_STATE_CHANGED_SIGNAL, - self._wait_state_changed_callback, - action, - ) - if act_connection.props.state != NM.ActiveConnectionState.DEACTIVATING: -- user_data = (handler_id, action) -+ user_data = action - self._ctx.client.deactivate_connection_async( - act_connection, - self._ctx.cancellable, - self._deactivate_connection_callback, - user_data, - ) -+ self._fallback_checker = GLib.timeout_source_new( -+ FALLBACK_CHECKER_INTERNAL * 1000 -+ ) -+ self._fallback_checker.set_callback( -+ self._deactivation_fallback_checker_callback, action -+ ) -+ self._fallback_checker.attach(self._ctx.context) -+ -+ def _clean_up(self): -+ if self._signal_handler: -+ if self._act_con: -+ self._act_con.handler_disconnect(self._signal_handler) -+ self._signal_handler = None -+ if self._fallback_checker: -+ self._fallback_checker.destroy() -+ self._fallback_checker = None - - def _wait_state_changed_callback(self, act_con, state, reason, action): - if self._ctx.is_cancelled(): -@@ -96,13 +116,13 @@ class ActiveConnection: - logging.debug( - "Connection deactivation succeeded on %s", self.devname, - ) -+ self._clean_up() - self._ctx.finish_async(action) - - def _deactivate_connection_callback(self, src_object, result, user_data): -- handler_id, action = user_data -+ action = user_data - if self._ctx.is_cancelled(): -- if self._act_con: -- self._act_con.handler_disconnect(handler_id) -+ self._clean_up() - return - - try: -@@ -116,16 +136,20 @@ class ActiveConnection: - "Connection is not active on {}, no need to " - "deactivate".format(self.devname) - ) -+ elif e.matches(Gio.io_error_quark(), Gio.IOErrorEnum.TIMED_OUT): -+ logging.debug( -+ f"{action} timeout, using fallback method to wait profile " -+ "deactivation" -+ ) -+ return - else: -- if self._act_con: -- self._act_con.handler_disconnect(handler_id) -+ self._clean_up() - self._ctx.fail( - NmstateLibnmError(f"{action} failed: error={e}") - ) - return - except Exception as e: -- if self._act_con: -- self._act_con.handler_disconnect(handler_id) -+ self._clean_up() - self._ctx.fail( - NmstateLibnmError( - f"BUG: Unexpected error when activating {self.devname} " -@@ -135,8 +159,7 @@ class ActiveConnection: - return - - if not success: -- if self._act_con: -- self._act_con.handler_disconnect(handler_id) -+ self._clean_up() - self._ctx.fail( - NmstateLibnmError( - f"{action} failed: error='None returned from " -@@ -144,6 +167,22 @@ class ActiveConnection: - ) - ) - -+ def _deactivation_fallback_checker_callback(self, action): -+ if self.devname: -+ self._nmdev = self._ctx.get_nm_dev(self.devname) -+ if self._nmdev: -+ self._act_con = self._nmdev.get_active_connection() -+ if ( -+ self._act_con -+ and self._act_con.props.state -+ != NM.ActiveConnectionState.DEACTIVATED -+ ): -+ return GLib.SOURCE_CONTINUE -+ -+ self._clean_up() -+ self._ctx.finish_async(action) -+ return GLib.SOURCE_REMOVE -+ - @property - def nm_active_connection(self): - return self._act_con -diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py -index 374a379..af7296f 100644 ---- a/libnmstate/nm/connection.py -+++ b/libnmstate/nm/connection.py -@@ -144,6 +144,13 @@ class ConnectionProfile: - self._delete_connection_callback, - user_data, - ) -+ self._fallback_checker = GLib.timeout_source_new( -+ FALLBACK_CHECKER_INTERNAL * 1000 -+ ) -+ self._fallback_checker.set_callback( -+ self._delete_fallback_checker_callback, action -+ ) -+ self._fallback_checker.attach(self._ctx.context) - - def activate(self): - if self.con_id: -@@ -504,11 +511,24 @@ class ConnectionProfile: - action = user_data - try: - success = src_object.delete_finish(result) -+ except GLib.Error as e: -+ if e.matches(Gio.io_error_quark(), Gio.IOErrorEnum.TIMED_OUT): -+ logging.debug( -+ f"{action} timeout, using fallback method to wait profile " -+ "deletion" -+ ) -+ return -+ else: -+ self._ctx.fail( -+ NmstateLibnmError(f"{action} failed with error: {e}") -+ ) -+ return - except Exception as e: - self._ctx.fail(NmstateLibnmError(f"{action} failed: error={e}")) - return - - if success: -+ self._fallback_checker_cleanup() - self._ctx.finish_async(action) - else: - self._ctx.fail( -@@ -518,6 +538,16 @@ class ConnectionProfile: - ) - ) - -+ def _delete_fallback_checker_callback(self, action): -+ if self.profile: -+ for nm_profile in self._ctx.client.get_connections(): -+ if nm_profile.get_uuid() == self.profile.get_uuid(): -+ return GLib.SOURCE_CONTINUE -+ -+ self._fallback_checker_cleanup() -+ self._ctx.finish_async(action) -+ return GLib.SOURCE_REMOVE -+ - def _reset_profile(self): - self._con_profile = None - --- -2.27.0 - diff --git a/SOURCES/BZ_1916073_retry_on_failure_when_activate.patch b/SOURCES/BZ_1916073_retry_on_failure_when_activate.patch deleted file mode 100644 index da7f372..0000000 --- a/SOURCES/BZ_1916073_retry_on_failure_when_activate.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 013860d2576a34a277178e6afba0935498dc4f72 Mon Sep 17 00:00:00 2001 -From: Fernando Fernandez Mancera -Date: Wed, 3 Feb 2021 11:59:05 +0100 -Subject: [PATCH] connection: retry on profile activation if libnm error - happened - -When activating a profile if NetworkManager fails during the activation, -Nmstate should retry it once. - -Signed-off-by: Fernando Fernandez Mancera ---- - libnmstate/nm/connection.py | 19 +++++++++++++++++-- - 1 file changed, 17 insertions(+), 2 deletions(-) - -diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py -index 5b9a3aee2..45cb69019 100644 ---- a/libnmstate/nm/connection.py -+++ b/libnmstate/nm/connection.py -@@ -180,7 +180,8 @@ def activate(self): - "BUG: Cannot activate a profile with empty profile id and " - "empty NM.Device" - ) -- user_data = action -+ retry = True -+ user_data = action, retry - self._ctx.register_async(action) - self._ctx.client.activate_connection_async( - self.profile, -@@ -267,7 +268,7 @@ def _active_connection_callback(self, src_object, result, user_data): - if self._ctx.is_cancelled(): - self._activation_clean_up() - return -- action = user_data -+ action, retry = user_data - - try: - nm_act_con = src_object.activate_connection_finish(result) -@@ -279,6 +280,20 @@ def _active_connection_callback(self, src_object, result, user_data): - ) - return - else: -+ if retry: -+ retry = False -+ user_data = action, retry -+ specific_object = None -+ logging.debug(f"Action {action} failed, trying again.") -+ self._ctx.client.activate_connection_async( -+ self.profile, -+ self.nmdevice, -+ specific_object, -+ self._ctx.cancellable, -+ self._active_connection_callback, -+ user_data, -+ ) -+ return - self._ctx.fail( - NmstateLibnmError(f"{action} failed: error={e}") - ) diff --git a/SOURCES/BZ_1918712_use_uuid_for_vlan_vxlan_parent.patch b/SOURCES/BZ_1918712_use_uuid_for_vlan_vxlan_parent.patch deleted file mode 100644 index 3c42770..0000000 --- a/SOURCES/BZ_1918712_use_uuid_for_vlan_vxlan_parent.patch +++ /dev/null @@ -1,214 +0,0 @@ -From a85b3dddf82f9e71774229740fbae6ea843d86d6 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Mon, 18 Jan 2021 15:55:43 +0800 -Subject: [PATCH 1/2] ifaces: Don't validate undesired interface for overbook - -There is no need to validate overbooked interface for undesired -controller interface. - -Unit test case included. - -Signed-off-by: Gris Ge ---- - libnmstate/ifaces/ifaces.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py -index 7723f43..ee75125 100644 ---- a/libnmstate/ifaces/ifaces.py -+++ b/libnmstate/ifaces/ifaces.py -@@ -437,6 +437,8 @@ class Ifaces: - """ - slave_master_map = {} - for iface in self._ifaces.values(): -+ if not (iface.is_changed or iface.is_desired) or not iface.is_up: -+ continue - for slave_name in iface.slaves: - cur_master = slave_master_map.get(slave_name) - if cur_master: --- -2.27.0 - - -From 644d8e5f5072caaba7151e66f211eceb02ae79c3 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Thu, 21 Jan 2021 20:43:34 +0800 -Subject: [PATCH 2/2] nm vlan/vxlan: Use uuid for VLAN/VxLAN parent - -When parent of VLAN/VxLAN is holding the same name of OVS bridge or OVS -port, NetworkManager will fail with error failed to find interface index -of that parent. - -The root cause is NetworkManager try to use user space interface as -VLAN/VxLAN parent. - -To workaround that, use profile UUID for `NM.SettingVlan.props.parent` -and `NM.SettingVxlan.props.parent`. - -Integration test case included. - -Signed-off-by: Gris Ge ---- - libnmstate/nm/applier.py | 98 +++++++++++++++++++++++++++++++++++-- - libnmstate/nm/connection.py | 7 +++ - 2 files changed, 100 insertions(+), 5 deletions(-) - -diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py -index 26a057f..8e38df5 100644 ---- a/libnmstate/nm/applier.py -+++ b/libnmstate/nm/applier.py -@@ -66,8 +66,6 @@ MASTER_IFACE_TYPES = ( - - - def apply_changes(context, net_state, save_to_disk): -- con_profiles = [] -- - if ( - not save_to_disk - and _has_ovs_interface_desired_or_changed(net_state) -@@ -87,6 +85,10 @@ def apply_changes(context, net_state, save_to_disk): - _create_proxy_ifaces_desired_state(ifaces_desired_state) - ) - -+ # A list of tuple holding both current ConnectionProfile and new/updated -+ # ConnectionProfile. -+ pending_con_profiles = [] -+ - for iface_desired_state in filter( - lambda s: s.get(Interface.STATE) != InterfaceState.ABSENT, - ifaces_desired_state, -@@ -131,7 +133,7 @@ def apply_changes(context, net_state, save_to_disk): - # anything besides state:up and not been marked as changed. - # We don't need to do this once we support querying on-disk - # configure -- con_profiles.append(cur_con_profile) -+ pending_con_profiles.append((cur_con_profile, None)) - continue - new_con_profile = _build_connection_profile( - context, -@@ -143,12 +145,25 @@ def apply_changes(context, net_state, save_to_disk): - set_conn = new_con_profile.profile.get_setting_connection() - set_conn.props.interface_name = iface_desired_state[Interface.NAME] - if cur_con_profile and cur_con_profile.profile: -- cur_con_profile.update(new_con_profile, save_to_disk) -- con_profiles.append(new_con_profile) -+ pending_con_profiles.append((cur_con_profile, new_con_profile)) - else: - # Missing connection, attempting to create a new one. -+ pending_con_profiles.append((None, new_con_profile)) -+ -+ pending_con_profiles = _use_uuid_for_parent( -+ context, pending_con_profiles, save_to_disk -+ ) -+ -+ con_profiles = [] -+ for cur_con_profile, new_con_profile in pending_con_profiles: -+ if cur_con_profile and new_con_profile: -+ cur_con_profile.update(new_con_profile, save_to_disk) -+ con_profiles.append(new_con_profile) -+ elif cur_con_profile is None and new_con_profile: - new_con_profile.add(save_to_disk) - con_profiles.append(new_con_profile) -+ elif cur_con_profile: -+ con_profiles.append(cur_con_profile) - context.wait_all_finish() - - _set_ifaces_admin_state(context, ifaces_desired_state, con_profiles) -@@ -655,3 +670,76 @@ def _mark_nm_external_subordinate_changed(context, net_state): - subordinate_iface = net_state.ifaces.get(subordinate) - if subordinate_iface: - subordinate_iface.mark_as_changed() -+ -+ -+def _use_uuid_for_parent(context, pending_con_profiles, save_to_disk): -+ """ -+ When parent of VLAN/VxLAN is holding the same name with -+ OVS bridge or OVS port, we should use UUID instead of interface name -+ """ -+ new_pending_con_profiles = [] -+ kernel_iface_name_to_uuid = {} -+ for cur_nm_profile in context.client.get_connections(): -+ connection_type = cur_nm_profile.get_connection_type() -+ if connection_type not in ( -+ NM.SETTING_OVS_BRIDGE_SETTING_NAME, -+ NM.SETTING_OVS_PORT_SETTING_NAME, -+ ): -+ kernel_iface_name_to_uuid[ -+ cur_nm_profile.get_interface_name() -+ ] = cur_nm_profile.get_uuid() -+ # Override existing kernel_iface_name_to_uuid with pending changes. -+ for cur_con_profile, new_con_profile in pending_con_profiles: -+ if new_con_profile and new_con_profile.profile: -+ uuid = new_con_profile.profile.get_uuid() -+ connection_type = new_con_profile.profile.get_connection_type() -+ iface_name = new_con_profile.profile.get_interface_name() -+ elif cur_con_profile and cur_con_profile.profile: -+ uuid = cur_con_profile.profile.get_uuid() -+ connection_type = cur_con_profile.profile.get_connection_type() -+ iface_name = cur_con_profile.profile.get_interface_name() -+ else: -+ continue -+ -+ if connection_type not in ( -+ NM.SETTING_OVS_BRIDGE_SETTING_NAME, -+ NM.SETTING_OVS_PORT_SETTING_NAME, -+ ): -+ kernel_iface_name_to_uuid[iface_name] = uuid -+ -+ for cur_con_profile, new_con_profile in pending_con_profiles: -+ new_pending_con_profiles.append((cur_con_profile, new_con_profile)) -+ if not new_con_profile: -+ continue -+ nm_profile = new_con_profile.profile -+ if not nm_profile: -+ continue -+ connection_type = nm_profile.get_connection_type() -+ nm_setting = None -+ if connection_type == NM.SETTING_VLAN_SETTING_NAME: -+ nm_setting = nm_profile.get_setting_vlan() -+ elif connection_type == NM.SETTING_VXLAN_SETTING_NAME: -+ nm_setting = nm_profile.get_setting_vxlan() -+ else: -+ continue -+ if not nm_setting: -+ continue -+ parent_iface_name = nm_setting.props.parent -+ parent_uuid = kernel_iface_name_to_uuid.get(parent_iface_name) -+ if parent_uuid: -+ updated_con_profile = connection.ConnectionProfile(context) -+ new_nm_settings = [] -+ for cur_nm_setting in nm_profile.get_settings(): -+ new_nm_setting = cur_nm_setting.duplicate() -+ if new_nm_setting.get_name() in ( -+ NM.SETTING_VLAN_SETTING_NAME, -+ NM.SETTING_VXLAN_SETTING_NAME, -+ ): -+ new_nm_setting.props.parent = parent_uuid -+ new_nm_settings.append(new_nm_setting) -+ updated_con_profile.create(new_nm_settings) -+ new_pending_con_profiles.pop() -+ new_pending_con_profiles.append( -+ (cur_con_profile, updated_con_profile) -+ ) -+ return new_pending_con_profiles -diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py -index af7296f..5b9a3ae 100644 ---- a/libnmstate/nm/connection.py -+++ b/libnmstate/nm/connection.py -@@ -63,6 +63,13 @@ class ConnectionProfile: - if self.con_id: - self.profile = self._ctx.client.get_connection_by_id(self.con_id) - -+ def import_by_uuid(self, uuid): -+ for nm_profile in self._ctx.client.get_connections(): -+ if nm_profile.get_uuid() == uuid: -+ self.profile = nm_profile -+ return -+ logging.debug(f"Failed to find {uuid} profile") -+ - def update(self, con_profile, save_to_disk=True): - flags = NM.SettingsUpdate2Flags.BLOCK_AUTOCONNECT - if save_to_disk: --- -2.27.0 - diff --git a/SOURCES/BZ_1931290-SRIOV-Do-not-create-VF-profiles-automatically.patch b/SOURCES/BZ_1931290-SRIOV-Do-not-create-VF-profiles-automatically.patch deleted file mode 100644 index 43d0dba..0000000 --- a/SOURCES/BZ_1931290-SRIOV-Do-not-create-VF-profiles-automatically.patch +++ /dev/null @@ -1,82 +0,0 @@ -From cc7e6da98cc992d2e6d8aa85cd78f02fb8ef8ac3 Mon Sep 17 00:00:00 2001 -From: Fernando Fernandez Mancera -Date: Sun, 21 Feb 2021 22:43:57 +0100 -Subject: [PATCH 2/5] SR-IOV: Do not create VF profiles automatically - -As VFs are Ethernet type and Nmstate is automatically adding them to the -desired state and marking them as desired, the profile is being created. -This is wrong as Nmstate should only wait for verification of the VFs. - -In order to fix this, the new VF interfaces are being marked as so. This -way Nmstate is not creating the profiles anymore. - -Integration test case added. - -Signed-off-by: Fernando Fernandez Mancera ---- - libnmstate/ifaces/ethernet.py | 10 ++++ - libnmstate/ifaces/ifaces.py | 1 + - libnmstate/nm/applier.py | 5 ++ - tests/integration/nm/sriov_test.py | 92 ++++++++++++++++++++++++++++++ - 4 files changed, 108 insertions(+) - create mode 100644 tests/integration/nm/sriov_test.py - -diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py -index 3e1bdc5d..f1ece5f5 100644 ---- a/libnmstate/ifaces/ethernet.py -+++ b/libnmstate/ifaces/ethernet.py -@@ -25,6 +25,9 @@ from libnmstate.schema import InterfaceState - from .base_iface import BaseIface - - -+IS_NEW_SR_IOV_VF = "_is_new_sr_iov_vf" -+ -+ - class EthernetIface(BaseIface): - def merge(self, other): - """ -@@ -57,6 +60,13 @@ class EthernetIface(BaseIface): - .get(Ethernet.SRIOV.TOTAL_VFS, 0) - ) - -+ @property -+ def is_new_sr_iov_vf(self): -+ return self.raw.get(IS_NEW_SR_IOV_VF) -+ -+ def mark_as_new_sr_iov_vf(self): -+ self.raw[IS_NEW_SR_IOV_VF] = True -+ - def create_sriov_vf_ifaces(self): - return [ - EthernetIface( -diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py -index 67ab91c4..a7af9712 100644 ---- a/libnmstate/ifaces/ifaces.py -+++ b/libnmstate/ifaces/ifaces.py -@@ -144,6 +144,7 @@ class Ifaces: - for new_iface in iface.create_sriov_vf_ifaces(): - if new_iface.name not in self._ifaces: - new_iface.mark_as_desired() -+ new_iface.mark_as_new_sr_iov_vf() - new_ifaces.append(new_iface) - for new_iface in new_ifaces: - self._ifaces[new_iface.name] = new_iface -diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py -index 8e38df54..cd319ffb 100644 ---- a/libnmstate/nm/applier.py -+++ b/libnmstate/nm/applier.py -@@ -119,6 +119,11 @@ def apply_changes(context, net_state, save_to_disk): - original_desired_iface_state = {} - if net_state.ifaces.get(ifname): - iface = net_state.ifaces[ifname] -+ if iface.type == InterfaceType.ETHERNET and iface.is_new_sr_iov_vf: -+ # For new vfs automatically added to the desired state is just -+ # for verification, Nmstate should not create a profile for -+ # them. -+ continue - if iface.is_desired: - original_desired_iface_state = iface.original_dict - if ( --- -2.29.2 - diff --git a/SOURCES/BZ_1931290-SRIOV-Remove-VF-interface-when-total-vfs-decrease.patch b/SOURCES/BZ_1931290-SRIOV-Remove-VF-interface-when-total-vfs-decrease.patch deleted file mode 100644 index 99e3e15..0000000 --- a/SOURCES/BZ_1931290-SRIOV-Remove-VF-interface-when-total-vfs-decrease.patch +++ /dev/null @@ -1,112 +0,0 @@ -From c55d39e8485a26490afc36d71fd9d20528ab6fd2 Mon Sep 17 00:00:00 2001 -From: Gris Ge -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 -Signed-off-by: Fernando Fernandez Mancera ---- - 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 - diff --git a/SOURCES/BZ_1931355-SRIOV-wait-VF-mount-decrease.patch b/SOURCES/BZ_1931355-SRIOV-wait-VF-mount-decrease.patch new file mode 100644 index 0000000..f215f9f --- /dev/null +++ b/SOURCES/BZ_1931355-SRIOV-wait-VF-mount-decrease.patch @@ -0,0 +1,166 @@ +From 80c97b27707b036f0a54988ade4bda3ccb342b34 Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Mon, 22 Feb 2021 12:03:11 +0100 +Subject: [PATCH 1/2] SR-IOV: increase the verification timeout if SR-IOV is + present + +Certain drivers like i40e take a long time to modify the VFs in the +kernel. Nmstate is timing out on verification because of that. In order +to fix this, nmstate is incresing the verification time if SR-IOV is +present on the desired state. + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Gris Ge +--- + libnmstate/ifaces/ethernet.py | 6 ++++++ + libnmstate/netapplier.py | 18 +++++++++++++++++- + 2 files changed, 23 insertions(+), 1 deletion(-) + +diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py +index 292b7bc..ca8501b 100644 +--- a/libnmstate/ifaces/ethernet.py ++++ b/libnmstate/ifaces/ethernet.py +@@ -65,6 +65,12 @@ class EthernetIface(BaseIface): + def is_peer(self): + return self._is_peer + ++ @property ++ def is_sriov(self): ++ return self.raw.get(Ethernet.CONFIG_SUBTREE, {}).get( ++ Ethernet.SRIOV_SUBTREE ++ ) ++ + def create_sriov_vf_ifaces(self): + return [ + EthernetIface( +diff --git a/libnmstate/netapplier.py b/libnmstate/netapplier.py +index cf208d1..3c5759b 100644 +--- a/libnmstate/netapplier.py ++++ b/libnmstate/netapplier.py +@@ -24,6 +24,7 @@ import time + + from libnmstate import validator + from libnmstate.error import NmstateVerificationError ++from libnmstate.schema import InterfaceType + + from .nmstate import create_checkpoints + from .nmstate import destroy_checkpoints +@@ -37,6 +38,7 @@ from .version import get_version + MAINLOOP_TIMEOUT = 35 + VERIFY_RETRY_INTERNAL = 1 + VERIFY_RETRY_TIMEOUT = 5 ++VERIFY_RETRY_TIMEOUT_INCREASE = 4 + + + def apply( +@@ -109,7 +111,13 @@ def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk): + plugin.apply_changes(net_state, save_to_disk) + verified = False + if verify_change: +- for _ in range(VERIFY_RETRY_TIMEOUT): ++ if _net_state_contains_sriov_interface(net_state): ++ # If SR-IOV is present, the verification timeout is being increased ++ # to avoid timeouts due to slow drivers like i40e. ++ verify_retry = VERIFY_RETRY_TIMEOUT * VERIFY_RETRY_TIMEOUT_INCREASE ++ else: ++ verify_retry = VERIFY_RETRY_TIMEOUT ++ for _ in range(verify_retry): + try: + _verify_change(plugins, net_state) + verified = True +@@ -120,6 +128,14 @@ def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk): + _verify_change(plugins, net_state) + + ++def _net_state_contains_sriov_interface(net_state): ++ for iface in net_state.ifaces.all_kernel_ifaces.values(): ++ if iface.type == InterfaceType.ETHERNET and iface.is_sriov: ++ return True ++ ++ return False ++ ++ + def _verify_change(plugins, net_state): + current_state = show_with_plugins(plugins) + net_state.verify(current_state) +-- +2.27.0 + + +From 439fe3a51a82060c5b62974c6c9fbdf403c4196b Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Mon, 22 Feb 2021 13:33:06 +0100 +Subject: [PATCH 2/2] SR-IOV: fail on verification if `total_vfs` does not + match vfs len + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Gris Ge +--- + libnmstate/ifaces/ethernet.py | 11 +++++++++++ + libnmstate/ifaces/ifaces.py | 14 ++++++++++++++ + 2 files changed, 25 insertions(+) + +diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py +index ca8501b..55772ce 100644 +--- a/libnmstate/ifaces/ethernet.py ++++ b/libnmstate/ifaces/ethernet.py +@@ -61,6 +61,14 @@ class EthernetIface(BaseIface): + .get(Ethernet.SRIOV.TOTAL_VFS, 0) + ) + ++ @property ++ def sriov_vfs(self): ++ return ( ++ self.raw.get(Ethernet.CONFIG_SUBTREE, {}) ++ .get(Ethernet.SRIOV_SUBTREE, {}) ++ .get(Ethernet.SRIOV.VFS_SUBTREE, []) ++ ) ++ + @property + def is_peer(self): + return self._is_peer +@@ -108,6 +116,9 @@ class EthernetIface(BaseIface): + for i in range(self.sriov_total_vfs, old_sriov_total_vfs) + ] + ++ def check_total_vfs_matches_vf_list(self, total_vfs): ++ return total_vfs == len(self.sriov_vfs) ++ + + def _capitalize_sriov_vf_mac(state): + vfs = ( +diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py +index 44c9e61..6c94a98 100644 +--- a/libnmstate/ifaces/ifaces.py ++++ b/libnmstate/ifaces/ifaces.py +@@ -238,6 +238,8 @@ class Ifaces: + if new_iface.name not in self._kernel_ifaces: + new_iface.mark_as_desired() + new_ifaces.append(new_iface) ++ else: ++ self._kernel_ifaces[new_iface.name].mark_as_desired() + for new_iface in new_ifaces: + self._kernel_ifaces[new_iface.name] = new_iface + +@@ -656,6 +658,18 @@ class Ifaces: + cur_iface.state_for_verify(), + ) + ) ++ elif ( ++ iface.type == InterfaceType.ETHERNET and iface.is_sriov ++ ): ++ if not cur_iface.check_total_vfs_matches_vf_list( ++ iface.sriov_total_vfs ++ ): ++ raise NmstateVerificationError( ++ "The NIC exceeded the waiting time for " ++ "verification and it is failing because " ++ "the `total_vfs` does not match the VF " ++ "list length." ++ ) + + def gen_dns_metadata(self, dns_state, route_state): + iface_metadata = dns_state.gen_metadata(self, route_state) +-- +2.27.0 + diff --git a/SOURCES/BZ_1931751-nmstate-fix-return-code.patch b/SOURCES/BZ_1931751-nmstate-fix-return-code.patch new file mode 100644 index 0000000..78b6774 --- /dev/null +++ b/SOURCES/BZ_1931751-nmstate-fix-return-code.patch @@ -0,0 +1,29 @@ +From b26ab850172a41557cad42cc011bd00d7c108c88 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Tue, 23 Feb 2021 13:52:19 +0800 +Subject: [PATCH] nmstatectl: Fix return code of set command + +The deprecated command `set` should still return the error like +old behaviour. + +Signed-off-by: Gris Ge +--- + nmstatectl/nmstatectl.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/nmstatectl/nmstatectl.py b/nmstatectl/nmstatectl.py +index df59942..c94d603 100644 +--- a/nmstatectl/nmstatectl.py ++++ b/nmstatectl/nmstatectl.py +@@ -323,7 +323,7 @@ def show(args): + + def set(args): + warnings.warn("Using 'set' is deprecated, use 'apply' instead.") +- apply(args) ++ return apply(args) + + + def apply(args): +-- +2.27.0 + diff --git a/SOURCES/BZ_1931784-SR-IOV-fail-on-verification-if-total_vfs-does-not-ma.patch b/SOURCES/BZ_1931784-SR-IOV-fail-on-verification-if-total_vfs-does-not-ma.patch deleted file mode 100644 index 6806d80..0000000 --- a/SOURCES/BZ_1931784-SR-IOV-fail-on-verification-if-total_vfs-does-not-ma.patch +++ /dev/null @@ -1,79 +0,0 @@ -From a43609607abe30b973f1cb78cb1754f1a9a91514 Mon Sep 17 00:00:00 2001 -From: Fernando Fernandez Mancera -Date: Mon, 22 Feb 2021 13:33:06 +0100 -Subject: [PATCH 4/5] SR-IOV: fail on verification if `total_vfs` does not - match vfs len - -Signed-off-by: Fernando Fernandez Mancera ---- - libnmstate/ifaces/ethernet.py | 11 +++++++++++ - libnmstate/ifaces/ifaces.py | 17 +++++++++++++++++ - 2 files changed, 28 insertions(+) - -diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py -index 1c3ca266..4903bde7 100644 ---- a/libnmstate/ifaces/ethernet.py -+++ b/libnmstate/ifaces/ethernet.py -@@ -52,6 +52,14 @@ class EthernetIface(BaseIface): - _capitalize_sriov_vf_mac(state) - return state - -+ @property -+ def sriov_vfs(self): -+ return ( -+ self.raw.get(Ethernet.CONFIG_SUBTREE, {}) -+ .get(Ethernet.SRIOV_SUBTREE, {}) -+ .get(Ethernet.SRIOV.VFS_SUBTREE, {}) -+ ) -+ - @property - def sriov_total_vfs(self): - return ( -@@ -109,6 +117,9 @@ class EthernetIface(BaseIface): - for i in range(self.sriov_total_vfs, old_sriov_total_vfs) - ] - -+ def check_total_vfs_matches_vf_list(self, total_vfs): -+ return total_vfs == len(self.sriov_vfs) -+ - - def _capitalize_sriov_vf_mac(state): - vfs = ( -diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py -index b212ebb5..1d30d0c6 100644 ---- a/libnmstate/ifaces/ifaces.py -+++ b/libnmstate/ifaces/ifaces.py -@@ -146,6 +146,11 @@ class Ifaces: - new_iface.mark_as_desired() - new_iface.mark_as_new_sr_iov_vf() - new_ifaces.append(new_iface) -+ else: -+ # When the VFs are being modified, all VFs link are -+ # being removed from kernel and created again. Nmstate -+ # must verify they have been created. -+ self._ifaces[new_iface.name].mark_as_desired() - for new_iface in new_ifaces: - self._ifaces[new_iface.name] = new_iface - -@@ -403,6 +408,18 @@ class Ifaces: - cur_iface.state_for_verify(), - ) - ) -+ elif ( -+ iface.type == InterfaceType.ETHERNET and iface.is_sriov -+ ): -+ if not cur_iface.check_total_vfs_matches_vf_list( -+ iface.sriov_total_vfs -+ ): -+ raise NmstateVerificationError( -+ "The NIC exceeded the waiting time for " -+ "verification and it is failing because " -+ "the `total_vfs` does not match the VF " -+ "list length." -+ ) - - def gen_dns_metadata(self, dns_state, route_state): - iface_metadata = dns_state.gen_metadata(self, route_state) --- -2.29.2 - diff --git a/SOURCES/BZ_1931784-SR-IOV-increase-the-verification-timeout-if-SR-IOV.patch b/SOURCES/BZ_1931784-SR-IOV-increase-the-verification-timeout-if-SR-IOV.patch deleted file mode 100644 index d801c0f..0000000 --- a/SOURCES/BZ_1931784-SR-IOV-increase-the-verification-timeout-if-SR-IOV.patch +++ /dev/null @@ -1,102 +0,0 @@ -From afb3f2dfeb5364e8a9a0bde4ad9062f1585a8795 Mon Sep 17 00:00:00 2001 -From: Fernando Fernandez Mancera -Date: Mon, 22 Feb 2021 12:03:11 +0100 -Subject: [PATCH 3/5] SR-IOV: increase the verification timeout if SR-IOV is - present - -Certain drivers like i40e take a long time to modify the VFs in the -kernel. Nmstate is timing out on verification because of that. In order -to fix this, nmstate is incresing the verification time if SR-IOV is -present on the desired state. - -Signed-off-by: Fernando Fernandez Mancera ---- - libnmstate/ifaces/ethernet.py | 5 +++++ - libnmstate/ifaces/ifaces.py | 4 ++++ - libnmstate/netapplier.py | 18 +++++++++++++++++- - 3 files changed, 26 insertions(+), 1 deletion(-) - -diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py -index f1ece5f5..1c3ca266 100644 ---- a/libnmstate/ifaces/ethernet.py -+++ b/libnmstate/ifaces/ethernet.py -@@ -67,6 +67,11 @@ class EthernetIface(BaseIface): - def mark_as_new_sr_iov_vf(self): - self.raw[IS_NEW_SR_IOV_VF] = True - -+ def is_sriov(self): -+ return self.raw.get(Ethernet.CONFIG_SUBTREE, {}).get( -+ Ethernet.SRIOV_SUBTREE, {} -+ ) -+ - def create_sriov_vf_ifaces(self): - return [ - EthernetIface( -diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py -index a7af9712..b212ebb5 100644 ---- a/libnmstate/ifaces/ifaces.py -+++ b/libnmstate/ifaces/ifaces.py -@@ -325,6 +325,10 @@ class Ifaces: - def current_ifaces(self): - return self._cur_ifaces - -+ @property -+ def all_ifaces(self): -+ return self._ifaces -+ - @property - def state_to_edit(self): - return [ -diff --git a/libnmstate/netapplier.py b/libnmstate/netapplier.py -index 24df4d56..6aa1ac07 100644 ---- a/libnmstate/netapplier.py -+++ b/libnmstate/netapplier.py -@@ -23,6 +23,7 @@ import time - - from libnmstate import validator - from libnmstate.error import NmstateVerificationError -+from libnmstate.schema import InterfaceType - - from .nmstate import create_checkpoints - from .nmstate import destroy_checkpoints -@@ -35,6 +36,7 @@ from .net_state import NetState - MAINLOOP_TIMEOUT = 35 - VERIFY_RETRY_INTERNAL = 1 - VERIFY_RETRY_TIMEOUT = 5 -+VERIFY_RETRY_TIMEOUT_INCREASE = 4 - - - def apply( -@@ -104,7 +106,13 @@ def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk): - plugin.apply_changes(net_state, save_to_disk) - verified = False - if verify_change: -- for _ in range(VERIFY_RETRY_TIMEOUT): -+ if _net_state_contains_sriov_interface(net_state): -+ # If SR-IOV is present, the verification timeout is being increased -+ # to avoid timeouts due to slow drivers like i40e. -+ verify_retry = VERIFY_RETRY_TIMEOUT * VERIFY_RETRY_TIMEOUT_INCREASE -+ else: -+ verify_retry = VERIFY_RETRY_TIMEOUT -+ for _ in range(verify_retry): - try: - _verify_change(plugins, net_state) - verified = True -@@ -115,6 +123,14 @@ def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk): - _verify_change(plugins, net_state) - - -+def _net_state_contains_sriov_interface(net_state): -+ for iface in net_state.ifaces.all_ifaces.values(): -+ if iface.type == InterfaceType.ETHERNET and iface.is_sriov: -+ return True -+ -+ return False -+ -+ - def _verify_change(plugins, net_state): - current_state = show_with_plugins(plugins) - net_state.verify(current_state) --- -2.29.2 - diff --git a/SOURCES/BZ_1932247-bridge-do-not-bring-up-existing-ports.patch b/SOURCES/BZ_1932247-bridge-do-not-bring-up-existing-ports.patch deleted file mode 100644 index 2b4baec..0000000 --- a/SOURCES/BZ_1932247-bridge-do-not-bring-up-existing-ports.patch +++ /dev/null @@ -1,38 +0,0 @@ -From cb4cbff0da01bb1e6546c2b28ef2760ec1f89f74 Mon Sep 17 00:00:00 2001 -From: Fernando Fernandez Mancera -Date: Wed, 24 Feb 2021 17:12:13 +0100 -Subject: [PATCH 5/5] bridge: do not bring up existing ports - -Nmstate should not try to bring up existing ports on a bridge when -modifying it. The ports will be bring up when being added to the it, if -the bridge is being modified later, the ports are not going to be -automatically up. - -Ref: https://bugzilla.redhat.com/1932247 - -Signed-off-by: Fernando Fernandez Mancera ---- - libnmstate/ifaces/ifaces.py | 5 + - tests/integration/nm/linux_bridge_test.py | 112 +++++++++++++++++++++- - 2 files changed, 116 insertions(+), 1 deletion(-) - -diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py -index 1d30d0c6..5f1f548d 100644 ---- a/libnmstate/ifaces/ifaces.py -+++ b/libnmstate/ifaces/ifaces.py -@@ -194,7 +194,12 @@ class Ifaces: - """ - for iface in self._ifaces.values(): - if iface.is_up and iface.is_master: -+ cur_iface = self.current_ifaces.get(iface.name) - for slave_name in iface.slaves: -+ if cur_iface and slave_name in cur_iface.slaves: -+ # Nmstate should not touch the port interface which has -+ # already been included in current interface. -+ continue - slave_iface = self._ifaces[slave_name] - if not slave_iface.is_desired and not slave_iface.is_up: - slave_iface.mark_as_up() --- -2.29.2 - 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 new file mode 100644 index 0000000..ea46af7 --- /dev/null +++ b/SOURCES/BZ_1932247-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/SOURCES/BZ_1932247-nm.applier-ignore-not-desired-unmanaged-ifaces.patch b/SOURCES/BZ_1932247-nm.applier-ignore-not-desired-unmanaged-ifaces.patch deleted file mode 100644 index 283f8fa..0000000 --- a/SOURCES/BZ_1932247-nm.applier-ignore-not-desired-unmanaged-ifaces.patch +++ /dev/null @@ -1,77 +0,0 @@ -From fb9352b902f8fec813c149e02e97c7014ef6399c Mon Sep 17 00:00:00 2001 -From: Fernando Fernandez Mancera -Date: Mon, 1 Mar 2021 16:25:57 +0100 -Subject: [PATCH] nm.applier: ignore not desired unmanaged ifaces - -Nmstate will ignore not desired unmanaged interfaces. If an existing -unmanaged port of a bridge is not being included in the desired state -bridge port list, it will not be removed. Basically, Nmstate will not be -able to remove unmanaged ports from a bridge. - -Signed-off-by: Fernando Fernandez Mancera ---- - libnmstate/ifaces/ifaces.py | 11 ++++++--- - libnmstate/nm/applier.py | 11 ++++++++- - tests/integration/linux_bridge_test.py | 1 + - tests/integration/nm/linux_bridge_test.py | 30 +++-------------------- - 4 files changed, 21 insertions(+), 32 deletions(-) - -diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py -index 5f1f548d..cfc306c6 100644 ---- a/libnmstate/ifaces/ifaces.py -+++ b/libnmstate/ifaces/ifaces.py -@@ -193,7 +193,7 @@ class Ifaces: - if not defiend in desire state - """ - for iface in self._ifaces.values(): -- if iface.is_up and iface.is_master: -+ if iface.is_desired and iface.is_up and iface.is_master: - cur_iface = self.current_ifaces.get(iface.name) - for slave_name in iface.slaves: - if cur_iface and slave_name in cur_iface.slaves: -@@ -353,14 +353,17 @@ class Ifaces: - - def _remove_unknown_interface_type_slaves(self): - """ -- When master containing slaves with unknown interface type, they should -- be removed from master slave list before verifying. -+ When master containing slaves with unknown interface type or down -+ state, they should be removed from master slave list before verifying. - """ - for iface in self._ifaces.values(): - if iface.is_up and iface.is_master and iface.slaves: - for slave_name in iface.slaves: - slave_iface = self._ifaces[slave_name] -- if slave_iface.type == InterfaceType.UNKNOWN: -+ if ( -+ slave_iface.type == InterfaceType.UNKNOWN -+ or slave_iface.state != InterfaceState.UP -+ ): - iface.remove_slave(slave_name) - - def verify(self, cur_iface_infos): -diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py -index cd319ffb..da2dab5b 100644 ---- a/libnmstate/nm/applier.py -+++ b/libnmstate/nm/applier.py -@@ -80,7 +80,16 @@ def apply_changes(context, net_state, save_to_disk): - _preapply_dns_fix(context, net_state) - _mark_nm_external_subordinate_changed(context, net_state) - -- ifaces_desired_state = net_state.ifaces.state_to_edit -+ ifaces_desired_state = [] -+ for iface in net_state.ifaces.all_ifaces.values(): -+ nm_dev = context.get_nm_dev(iface.name) -+ if nm_dev and not nm_dev.get_managed() and not iface.is_desired: -+ # We don't change NM.Device from unmanaged to managed unless -+ # been asked explicitly in desire state -+ continue -+ if iface.is_changed or iface.is_desired: -+ ifaces_desired_state.append(iface.to_dict()) -+ - ifaces_desired_state.extend( - _create_proxy_ifaces_desired_state(ifaces_desired_state) - ) --- -2.29.2 - diff --git a/SOURCES/BZ_1933538-bridge-bond-New-property-Interface.COPY_MAC_FROM.patch b/SOURCES/BZ_1933538-bridge-bond-New-property-Interface.COPY_MAC_FROM.patch deleted file mode 100644 index 3da7bb0..0000000 --- a/SOURCES/BZ_1933538-bridge-bond-New-property-Interface.COPY_MAC_FROM.patch +++ /dev/null @@ -1,146 +0,0 @@ -From 34b689a86c7cd4bcf5ab5cf7d903acba7d60f4be Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Wed, 10 Feb 2021 23:28:37 +0800 -Subject: [PATCH] bridge/bond: New property `Interface.COPY_MAC_FROM` - -Introducing `Interface.COPY_MAC_FROM` allowing bridge or bond -to use MAC address from specified port. - -Example: - -```yaml ---- -interfaces: -- name: bond99 - type: bond - state: up - copy-mac-from: eth1 - link-aggregation: - mode: balance-rr - port: - - eth2 - - eth1 -``` - -Integration test case included. - -Signed-off-by: Gris Ge -Signed-off-by: Fernando Fernandez Mancera ---- - libnmstate/ifaces/base_iface.py | 14 +++++++++++ - libnmstate/ifaces/ifaces.py | 30 +++++++++++++++++++++++ - libnmstate/schema.py | 1 + - libnmstate/schemas/operational-state.yaml | 4 +++ - tests/integration/bond_test.py | 13 ++++++++++ - tests/integration/linux_bridge_test.py | 14 +++++++++++ - 6 files changed, 76 insertions(+) - -diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py -index b4ade867..3dbcfe52 100644 ---- a/libnmstate/ifaces/base_iface.py -+++ b/libnmstate/ifaces/base_iface.py -@@ -391,6 +391,20 @@ class BaseIface: - for family, rules in route_rule_metadata.items(): - self.raw[family][BaseIface.ROUTE_RULES_METADATA] = rules - -+ @property -+ def copy_mac_from(self): -+ return self._info.get(Interface.COPY_MAC_FROM) -+ -+ def apply_copy_mac_from(self, mac): -+ """ -+ * Add MAC to original desire. -+ * Remove Interface.COPY_MAC_FROM from original desire. -+ * Update MAC of merge iface -+ """ -+ self.raw[Interface.MAC] = mac -+ self._origin_info[Interface.MAC] = mac -+ self._origin_info.pop(Interface.COPY_MAC_FROM, None) -+ - - def _remove_empty_description(state): - if state.get(Interface.DESCRIPTION) == "": -diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py -index cfc306c6..1e4d2231 100644 ---- a/libnmstate/ifaces/ifaces.py -+++ b/libnmstate/ifaces/ifaces.py -@@ -101,12 +101,42 @@ class Ifaces: - self._validate_unknown_slaves() - self._mark_vf_interface_as_absent_when_sriov_vf_decrease() - self._validate_unknown_parent() -+ self._apply_copy_mac_from() - self._gen_metadata() - for iface in self._ifaces.values(): - iface.pre_edit_validation_and_cleanup() - - self._pre_edit_validation_and_cleanup() - -+ def _apply_copy_mac_from(self): -+ for iface in self._ifaces.values(): -+ if iface.type not in ( -+ InterfaceType.LINUX_BRIDGE, -+ InterfaceType.BOND, -+ ): -+ continue -+ if not iface.copy_mac_from: -+ continue -+ -+ if iface.copy_mac_from not in iface.slaves: -+ raise NmstateValueError( -+ f"The interface {iface.name} is holding invalid " -+ f"{Interface.COPY_MAC_FROM} property " -+ f"as {iface.copy_mac_from} is not in the port " -+ f"list: {iface.port}" -+ ) -+ port_iface = self._ifaces.get(iface.copy_mac_from) -+ # TODO: bridge/bond might refering the mac from new veth in the -+ # same desire state, it too complex to support that. -+ if not port_iface: -+ raise NmstateValueError( -+ f"The interface {iface.name} is holding invalid " -+ f"{Interface.COPY_MAC_FROM} property " -+ f"as the port {iface.copy_mac_from} does not exists yet" -+ ) -+ -+ iface.apply_copy_mac_from(port_iface.mac) -+ - def _create_virtual_slaves(self): - """ - Certain master interface could have virtual slaves which does not -diff --git a/libnmstate/schema.py b/libnmstate/schema.py -index 8a86c48d..455dbf8f 100644 ---- a/libnmstate/schema.py -+++ b/libnmstate/schema.py -@@ -44,6 +44,7 @@ class Interface: - - MAC = "mac-address" - MTU = "mtu" -+ COPY_MAC_FROM = "copy-mac-from" - - - class Route: -diff --git a/libnmstate/schemas/operational-state.yaml b/libnmstate/schemas/operational-state.yaml -index d856aa5c..8fdeaeec 100644 ---- a/libnmstate/schemas/operational-state.yaml -+++ b/libnmstate/schemas/operational-state.yaml -@@ -249,6 +249,8 @@ definitions: - type: string - enum: - - bond -+ copy-mac-from: -+ type: string - link-aggregation: - type: object - properties: -@@ -267,6 +269,8 @@ definitions: - - $ref: "#/definitions/interface-linux-bridge/ro" - ro: - properties: -+ copy-mac-from: -+ type: string - bridge: - type: object - properties: --- -2.29.2 - diff --git a/SOURCES/nmstate-0.3.4.tar.gz.asc b/SOURCES/nmstate-0.3.4.tar.gz.asc deleted file mode 100644 index ac2c220..0000000 --- a/SOURCES/nmstate-0.3.4.tar.gz.asc +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQIzBAABCAAdFiEEfUQ+BAINyWGvqJXerIciWuEsPqMFAl8a02UACgkQrIciWuEs -PqMSmg//T/2C0mP+zb1pnIfcPZvc8dlNgnvtTIN8EK23b6UvxrFYKuPmqRw+Dsir -N/9enPTUgQKAOtZs7BdtZlCmsaU2bWAF11UgRY+gcSkSVeG0j/kxHLG3sE4RbFiD -QPKJrqRE6m+ybTOiJ0oVXkR7f2i/AVmZE3+eZHn1TzHQoKZA8MJyExYWmk7wMkfG -KzE7jvZQ1M4Q6aZKxo4wjAkhAhFLio9HhWnl8z1bLpWWFVHqqMJ04QniDsepczCm -ISr6grG2TW6bS93lRCdDkS4yGCAYrwZ/5eyN5eOTd/et7FqG/ExFHdVaaro5I1W5 -cbOYyZ1cI/avA9vCWCkC7DUJOh3i5BzzhHaxS65qqpM7fiLIrHZhaLQaLByMO48d -zo1wDEwIyNvuP4bIVwRycuDhtcLnPs5QwVbfW4HKkn4ULO+inr3lJk8V3ZZ3Ghmz -qKCrpteJTK/yJl9N2MrXxPvYYe388m4A6GGSVml4mYCd2ZMBrQ8k8fSPdlodmzVJ -J5gpeJRqm9sdrbv7tmuDfNOjAu0o9MP0/OSA0Lb5ho3pyylGnhsZ7Zkwbn2U/1b2 -zgPmVWJqRhjq01VgderCOerxow7OvetNicrNg/9e7+eFAHV7VUowdKf3vCyk0+nl -WGeZLxi21w2Q2RH1ThPo6uMxL3pIp7dsbVrqM7oLpUoZzGtFnq8= -=4Hsb ------END PGP SIGNATURE----- diff --git a/SOURCES/nmstate-1.0.2.tar.gz.asc b/SOURCES/nmstate-1.0.2.tar.gz.asc new file mode 100644 index 0000000..ef664a4 --- /dev/null +++ b/SOURCES/nmstate-1.0.2.tar.gz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCAAdFiEEfUQ+BAINyWGvqJXerIciWuEsPqMFAmAueEYACgkQrIciWuEs +PqPJxw//UmWdCJgoClFkEpWqWUkjMmfkGh70PoxtuOeNrAYwHv9zCHDBFjLtaDG1 +18+jakwrVIlTiFHZqfz1g3o0Te86w5rKiU2y0FBtBPZ1cdcJZk2Is5wb/JJo78n+ +9sWRfZmSN0SMiJ5HfzhTdZ2RsZYRSaDPSUxchRY03LzsBusxoK8swWu9oUHqmYKd +S3k4skP5ZQvpHtKzq9w1lfU4YAw42sRvXHW/++HqGgE0rypf+Wlcu9C+It9kVLCr +3rdp8iTGTg+LRg7LxFmEsRlmPpxhO25LaxjFvYSFnhE94xOt28KXeHBYs8hPPRwh ++z2w6zJ3hgIrLh10IPzePTWk//KNWDRaAJXQTCma1UE4jdL3+wbxb8H3vl5VCrBU +3fuj3JwfvFU1NuDf+yuJ0sCKzNXaAzpYYgfIaCaPdtBpg5jl2DTEfEF8QZKYuJDU +ueCo6reBAlwJzce433aSzBXshFbHG/RdD09duS3p84Dn6ljEN3GfJwUAC9s9TsAQ +U5+rWog6zMpVke/9yqwEf1KmqtLM3/+Ih30CHb3ZoPTf05KB14k0d1CLDdC9d9dy +gN0w8xjdTUXbUXW/XIvRVX9KWqyNI6lnZoL0MWzPwUmMxwPJkRpAVpLKpgyUrVpD +yjtLTFDZJNmfmbi2b0myFFcc2chaXmYlpLCP8vfRYJA3mCee6Xg= +=b/Mh +-----END PGP SIGNATURE----- diff --git a/SPECS/nmstate.spec b/SPECS/nmstate.spec index 1850ef8..06262d2 100644 --- a/SPECS/nmstate.spec +++ b/SPECS/nmstate.spec @@ -3,39 +3,17 @@ %define libname libnmstate Name: nmstate -Version: 0.3.4 -Release: 27%{?dist} +Version: 1.0.2 +Release: 5%{?dist} Summary: Declarative network manager API License: LGPLv2+ URL: https://github.com/%{srcname}/%{srcname} Source0: %{url}/releases/download/v%{version}/%{srcname}-%{version}.tar.gz Source1: %{url}/releases/download/v%{version}/%{srcname}-%{version}.tar.gz.asc Source2: https://www.nmstate.io/nmstate.gpg -Patch1: BZ_1858762-hide_ovs_patch_port_mtu.patch -Patch2: BZ_1861263-handle-external-managed-interface.patch -Patch3: BZ_1861668_ignore_unknown_iface.patch -Patch4: BZ_1862025-remove_existing_profiles.patch -Patch5: BZ_1858758-fix_ovs_bond.patch -Patch6: BZ_1859844-fix_converting_memory_only.patch -Patch7: BZ_1866269-preserve_nm_uuid_in_ovsdb.patch -Patch8: BZ_1869345_ovsdb_remove_all_ports.patch -Patch9: BZ_1887349-Allow-duplicate-iface-name-in-ovs.patch -Patch10: BZ_1890497-nm-bond-Ignore-ad_actor_system-00-00-00-00-00-00.patch -Patch11: BZ_1890497-nm.ipv6-call-clear_routing_rules-when-creating-the-s.patch -Patch12: BZ_1901571_do_not_check_ovs_daemon_when_showing.patch -Patch13: BZ_1904889-do-not-remove-unmanaged-ovs-bridge.patch -Patch14: BZ_1910193-support-multiple-gateways.patch -Patch15: BZ_1908724-sriov-use-verification-retry-to-wait-VF-been-created.patch -Patch16: BZ_1916073_better-handling-for-timeout.patch -Patch17: BZ_1918712_use_uuid_for_vlan_vxlan_parent.patch -Patch18: BZ_1916073_retry_on_failure_when_activate.patch -Patch19: BZ_1931290-SRIOV-Remove-VF-interface-when-total-vfs-decrease.patch -Patch20: BZ_1931290-SRIOV-Do-not-create-VF-profiles-automatically.patch -Patch21: BZ_1931784-SR-IOV-increase-the-verification-timeout-if-SR-IOV.patch -Patch22: BZ_1931784-SR-IOV-fail-on-verification-if-total_vfs-does-not-ma.patch -Patch23: BZ_1932247-bridge-do-not-bring-up-existing-ports.patch -Patch24: BZ_1932247-nm.applier-ignore-not-desired-unmanaged-ifaces.patch -Patch25: BZ_1933538-bridge-bond-New-property-Interface.COPY_MAC_FROM.patch +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 BuildArch: noarch BuildRequires: python3-devel BuildRequires: python3-setuptools @@ -62,6 +40,8 @@ Recommends: NetworkManager-config-server # required for OVS and team support Suggests: NetworkManager-ovs Suggests: NetworkManager-team +Requires: nispor +Requires: python3dist(varlink) %package -n nmstate-plugin-ovsdb Summary: nmstate plugin for OVS database manipulation @@ -106,53 +86,58 @@ gpgv2 --keyring ./gpgkey-mantainers.gpg %{SOURCE1} %{SOURCE0} %{python3_sitelib}/%{libname}/plugins/__pycache__/nmstate_plugin_ovsdb* %changelog -* Wed Mar 03 2021 Fernando Fernandez Mancera - 0.3.4-27 -- Introduce `Interface.COPY_MAC_FROM` from bond and bridge. RHBZ#1933538 +* Wed Mar 03 2021 Fernando Fernandez Mancera - 1.0.2-5 +- New patch for fixing unmanaged interfaces being managed. RHBZ#1932247 -* Wed Mar 03 2021 Fernando Fernandez Mancera - 0.3.4-26 -- New patch do not activating SR-IOV VFs automatically. RHBZ#1931290 -- New patch fixing Nmstate waits when SR-IOV VFs are decreased. RHBZ#1931784 -- New patch fixing Nmstate activating unmanaged bridge ports. RHBZ#1932247 +* Tue Feb 23 2021 Gris Ge - 1.0.2-4 +- New patch for SRIOV decrease VF amount. RHBZ#1931355 -* Fri Feb 05 2021 Gris Ge - 0.3.4-25 -- Remove patch for fixing the autoconnect on existing profile. RHBZ#1918712 +* Tue Feb 23 2021 Gris Ge - 1.0.2-3 +- Fix actiation failure when decrease VF mount on i40e. RHBZ#1931355 -* Thu Feb 04 2021 Gris Ge - 0.3.4-24 -- New patch fixing activation failure with 1000 interfaces. RHBZ#1916073 +* Tue Feb 23 2021 Gris Ge - 1.0.2-2 +- Fix nmstatectl return code of `set` command. RHBZ#1931751 -* Wed Feb 03 2021 Gris Ge - 0.3.4-23 -- Enforcing autoconnect on existing profile. RHBZ#1918712 +* Fri Feb 19 2021 Gris Ge - 1.0.2-1 +- Upgrade to 1.0.2. -* Fri Jan 22 2021 Gris Ge - 0.3.4-22 -- Fix creating VLAN/VxLAN over interface also used for OVS. RHBZ#1918712 +* Wed Feb 10 2021 Fernando Fernandez Mancera - 1.0.2-0.3 +- Fix sources name -* Sun Jan 17 2021 Gris Ge - 0.3.4-21 -- Additional patch for profile deactivation and deletion. RHBZ#1916073 +* Wed Feb 10 2021 Fernando Fernandez Mancera - 1.0.2-0.2 +- Upgrade to 1.0.2 alpha 2 -* Thu Jan 14 2021 Fernando Fernandez Mancera - 0.3.4-20 -- Better handling for timeout on activation. RHBZ#1916073 +* Tue Jan 26 2021 Fernando Fernandez Mancera - 1.0.2-0.1 +- Upgrade to 1.0.2 alpha 1 -* Mon Jan 04 2021 Fernando Fernandez Mancera - 0.3.4-19 -- Use verification retry to wait SR-IOV VF been created. RHBZ#1908724 +* Tue Jan 19 2021 Fernando Fernandez Mancera - 1.0.1-1 +- Upgrade to 1.0.1. RHBZ#1881287 -* Wed Dec 23 2020 Gris Ge - 0.3.4-18 -- Support multiple gateways. RHBZ#1910193 +* Tue Jan 05 2021 Gris Ge - 1.0.1-0.1 +- Upgrade to 1.0.1 alpha 1 -* Mon Dec 07 2020 Gris Ge - 0.3.4-17 -- Rebuild to retrigger the CI gating. RHBZ#1904889 +* Tue Dec 08 2020 Fernando Fernandez Mancera - 1.0.0-1 +- Upgrade to 1.0.0 -* Mon Dec 07 2020 Gris Ge - 0.3.4-16 -- Don't remove unmanaged OVS interface. RHBZ#1904889 +* Mon Nov 16 2020 Gris Ge - 1.0.0-0.1 +- Upgrade to 1.0.0 alpha 1 -* Thu Nov 26 2020 Gris Ge - 0.3.4-15 -- Fix `libnmstate.show()` in container with OVS bridge. RHBZ#1901571 +* Wed Oct 28 2020 Fernando Fernandez Mancera - 0.4.1-2 +- Allow VRF port to hold IP information -* Wed Nov 04 2020 Fernando Fernandez Mancera - 0.3.4-14 -- Ignore bond zero ad_actor_system. RHBZ#1890497 -- Fix clear IPv6 routing rules. +* Thu Oct 22 2020 Fernando Fernandez Mancera - 0.4.1-1 +- Upgrade to 0.4.1 -* Wed Oct 14 2020 Gris Ge - 0.3.4-13 -- Allowing duplicate interface name of ovs. RHBZ#1887349 +* Tue Oct 20 2020 Fernando Fernandez Mancera - 0.4.0-3 +- Add nispor as a dependency for CI gating + +* Tue Oct 20 2020 Fernando Fernandez Mancera - 0.4.0-2 +- Rebuild for CI gating +- Remove old patches from the repository + +* Mon Sep 14 2020 Fernando Fernandez Mancera - 0.4.0-1 +- Upgrade to 0.4.0 +- Sync. up with upstream spec file. * Tue Aug 18 2020 Gris Ge - 0.3.4-12 - New patch: OVSDB: Allowing remove all OVS ports. RHBZ#1869345