From a764ed7069830d87fceba02efc09ac0611fd32e5 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 6 Apr 2021 09:33:02 -0400 Subject: [PATCH] import nmstate-0.3.4-27.el8_3 --- ...not-create-VF-profiles-automatically.patch | 82 ++++++++++ ...VF-interface-when-total-vfs-decrease.patch | 112 ++++++++++++++ ...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 +++++ ...-ignore-not-desired-unmanaged-ifaces.patch | 77 +++++++++ ...New-property-Interface.COPY_MAC_FROM.patch | 146 ++++++++++++++++++ SPECS/nmstate.spec | 17 +- 8 files changed, 652 insertions(+), 1 deletion(-) create mode 100644 SOURCES/BZ_1931290-SRIOV-Do-not-create-VF-profiles-automatically.patch create mode 100644 SOURCES/BZ_1931290-SRIOV-Remove-VF-interface-when-total-vfs-decrease.patch create mode 100644 SOURCES/BZ_1931784-SR-IOV-fail-on-verification-if-total_vfs-does-not-ma.patch create mode 100644 SOURCES/BZ_1931784-SR-IOV-increase-the-verification-timeout-if-SR-IOV.patch create mode 100644 SOURCES/BZ_1932247-bridge-do-not-bring-up-existing-ports.patch create mode 100644 SOURCES/BZ_1932247-nm.applier-ignore-not-desired-unmanaged-ifaces.patch create mode 100644 SOURCES/BZ_1933538-bridge-bond-New-property-Interface.COPY_MAC_FROM.patch 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 new file mode 100644 index 0000000..43d0dba --- /dev/null +++ b/SOURCES/BZ_1931290-SRIOV-Do-not-create-VF-profiles-automatically.patch @@ -0,0 +1,82 @@ +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 new file mode 100644 index 0000000..99e3e15 --- /dev/null +++ b/SOURCES/BZ_1931290-SRIOV-Remove-VF-interface-when-total-vfs-decrease.patch @@ -0,0 +1,112 @@ +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_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 new file mode 100644 index 0000000..6806d80 --- /dev/null +++ b/SOURCES/BZ_1931784-SR-IOV-fail-on-verification-if-total_vfs-does-not-ma.patch @@ -0,0 +1,79 @@ +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 new file mode 100644 index 0000000..d801c0f --- /dev/null +++ b/SOURCES/BZ_1931784-SR-IOV-increase-the-verification-timeout-if-SR-IOV.patch @@ -0,0 +1,102 @@ +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 new file mode 100644 index 0000000..2b4baec --- /dev/null +++ b/SOURCES/BZ_1932247-bridge-do-not-bring-up-existing-ports.patch @@ -0,0 +1,38 @@ +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.applier-ignore-not-desired-unmanaged-ifaces.patch b/SOURCES/BZ_1932247-nm.applier-ignore-not-desired-unmanaged-ifaces.patch new file mode 100644 index 0000000..283f8fa --- /dev/null +++ b/SOURCES/BZ_1932247-nm.applier-ignore-not-desired-unmanaged-ifaces.patch @@ -0,0 +1,77 @@ +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 new file mode 100644 index 0000000..3da7bb0 --- /dev/null +++ b/SOURCES/BZ_1933538-bridge-bond-New-property-Interface.COPY_MAC_FROM.patch @@ -0,0 +1,146 @@ +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/SPECS/nmstate.spec b/SPECS/nmstate.spec index c7f3b10..1850ef8 100644 --- a/SPECS/nmstate.spec +++ b/SPECS/nmstate.spec @@ -4,7 +4,7 @@ Name: nmstate Version: 0.3.4 -Release: 25%{?dist} +Release: 27%{?dist} Summary: Declarative network manager API License: LGPLv2+ URL: https://github.com/%{srcname}/%{srcname} @@ -29,6 +29,13 @@ Patch15: BZ_1908724-sriov-use-verification-retry-to-wait-VF-been-created. 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 BuildArch: noarch BuildRequires: python3-devel BuildRequires: python3-setuptools @@ -99,6 +106,14 @@ 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 - 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 + * Fri Feb 05 2021 Gris Ge - 0.3.4-25 - Remove patch for fixing the autoconnect on existing profile. RHBZ#1918712