diff --git a/SOURCES/BZ_2128555-ip-allow-extra-IP-address-found-in-verification-stag.patch b/SOURCES/BZ_2128555-ip-allow-extra-IP-address-found-in-verification-stag.patch
new file mode 100644
index 0000000..1707467
--- /dev/null
+++ b/SOURCES/BZ_2128555-ip-allow-extra-IP-address-found-in-verification-stag.patch
@@ -0,0 +1,79 @@
+From 316f4fc3333627bcd3aef44c4a469cd6c04360ef Mon Sep 17 00:00:00 2001
+From: Gris Ge <fge@redhat.com>
+Date: Tue, 20 Sep 2022 21:35:47 +0800
+Subject: [PATCH 2/2] ip: allow extra IP address found in verification stage
+
+When nmstate applying the network state, there might be another tool
+changing the IP addresses of interface, which lead to verification error
+as extra IP address found. This is valid use case in kubernetes-nmstate
+where keepalived is trying to add VIP(192.168.111.4) to certain interface.
+
+To support that, we introduce `InterfaceIP.ALLOW_EXTRA_ADDRESS` with
+default set to true, nmstate verification will ignore extra IP address
+after applied.
+
+Considering this is a very corner case, and could make the life of of
+OpenshiftSDN engineer easier, I would suggest we accept this breaker of
+API behavior.
+
+It is hard to reproduce it in integration test case, hence only added
+unit test cases.
+
+Signed-off-by: Gris Ge <fge@redhat.com>
+---
+ libnmstate/ifaces/base_iface.py     | 20 ++++++
+ libnmstate/schema.py                |  1 +
+ tests/lib/ifaces/base_iface_test.py | 98 +++++++++++++++++++++++++++++
+ tests/lib/testlib/constants.py      |  2 +
+ 4 files changed, 121 insertions(+)
+
+diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py
+index e1b45617..fb2b7bb6 100644
+--- a/libnmstate/ifaces/base_iface.py
++++ b/libnmstate/ifaces/base_iface.py
+@@ -403,6 +403,10 @@ class BaseIface:
+     def match(self, other):
+         self_state = self.state_for_verify()
+         other_state = other.state_for_verify()
++        for family in (Interface.IPV4, Interface.IPV6):
++            apply_allow_extra_address(
++                self_state.get(family, {}), other_state.get(family, {})
++            )
+         return state_match(self_state, other_state)
+ 
+     def state_for_verify(self):
+@@ -537,3 +541,19 @@ def _convert_ovs_external_ids_values_to_string(iface_info):
+     )
+     for key, value in external_ids.items():
+         external_ids[key] = str(value)
++
++
++# When `ALLOW_EXTRA_ADDRESS:True`, we should remove extra IP address in
++# current.
++def apply_allow_extra_address(desire_ip_state, current_ip_state):
++    # By default, we allow extra IP found during verification stage in order
++    # to make the life of OpenshiftSDN easier for this corner case.
++    if desire_ip_state.get(InterfaceIP.ALLOW_EXTRA_ADDRESS, True):
++        desire_addresses = desire_ip_state.get(InterfaceIP.ADDRESS, [])
++        new_cur_addresses = [
++            addr
++            for addr in current_ip_state.get(InterfaceIP.ADDRESS, [])
++            if addr in desire_addresses
++        ]
++        current_ip_state[InterfaceIP.ADDRESS] = new_cur_addresses
++        desire_ip_state.pop(InterfaceIP.ALLOW_EXTRA_ADDRESS, None)
+diff --git a/libnmstate/schema.py b/libnmstate/schema.py
+index 17daf8f1..76418bf0 100644
+--- a/libnmstate/schema.py
++++ b/libnmstate/schema.py
+@@ -142,6 +142,7 @@ class InterfaceIP:
+     ADDRESS = "address"
+     ADDRESS_IP = "ip"
+     ADDRESS_PREFIX_LENGTH = "prefix-length"
++    ALLOW_EXTRA_ADDRESS = "allow-extra-address"
+     DHCP = "dhcp"
+     AUTO_DNS = "auto-dns"
+     AUTO_GATEWAY = "auto-gateway"
+-- 
+2.37.3
+
diff --git a/SOURCES/BZ_2139698-nm-sriov-Do-not-touch-SR-IOV-if-not-desired.patch b/SOURCES/BZ_2139698-nm-sriov-Do-not-touch-SR-IOV-if-not-desired.patch
new file mode 100644
index 0000000..e6a4dae
--- /dev/null
+++ b/SOURCES/BZ_2139698-nm-sriov-Do-not-touch-SR-IOV-if-not-desired.patch
@@ -0,0 +1,54 @@
+From 2786e426173ed4a930dca23e18756123fc9b0e3a Mon Sep 17 00:00:00 2001
+From: Gris Ge <fge@redhat.com>
+Date: Mon, 26 Sep 2022 14:42:28 +0800
+Subject: [PATCH 1/2] nm sriov: Do not touch SR-IOV if not desired
+
+We should not create SRIOV settings in NetworkManager if that is not
+desired.
+
+Integration test case included.
+Manual test been done on Mellanox MT27710(mlx5).
+
+Signed-off-by: Gris Ge <fge@redhat.com>
+---
+ libnmstate/nm/connection.py        |  2 +-
+ libnmstate/nm/sriov.py             |  8 ++--
+ tests/integration/nm/sriov_test.py | 62 ++++++++++++++++++++++++++++++
+ 3 files changed, 67 insertions(+), 5 deletions(-)
+
+diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py
+index 9beb7d18..535179ef 100644
+--- a/libnmstate/nm/connection.py
++++ b/libnmstate/nm/connection.py
+@@ -210,7 +210,7 @@ def create_new_nm_simple_conn(iface, nm_profile):
+     if vxlan_setting:
+         settings.append(vxlan_setting)
+ 
+-    sriov_setting = create_sriov_setting(iface_info, nm_profile)
++    sriov_setting = create_sriov_setting(iface, nm_profile)
+     if sriov_setting:
+         settings.append(sriov_setting)
+ 
+diff --git a/libnmstate/nm/sriov.py b/libnmstate/nm/sriov.py
+index 4aa73e86..74513cb7 100644
+--- a/libnmstate/nm/sriov.py
++++ b/libnmstate/nm/sriov.py
+@@ -47,11 +47,11 @@ SRIOV_NMSTATE_TO_NM_MAP = {
+ }
+ 
+ 
+-def create_setting(iface_state, base_con_profile):
++def create_setting(iface, base_con_profile):
+     sriov_setting = None
+-    sriov_config = iface_state.get(Ethernet.CONFIG_SUBTREE, {}).get(
+-        Ethernet.SRIOV_SUBTREE
+-    )
++    sriov_config = iface.original_desire_dict.get(
++        Ethernet.CONFIG_SUBTREE, {}
++    ).get(Ethernet.SRIOV_SUBTREE)
+ 
+     if base_con_profile:
+         sriov_setting = base_con_profile.get_setting_by_name(
+-- 
+2.37.3
+
diff --git a/SOURCES/BZ_2149048-ip-Preserve-the-IP-address-order-when-applying.patch b/SOURCES/BZ_2149048-ip-Preserve-the-IP-address-order-when-applying.patch
new file mode 100644
index 0000000..e6cf71f
--- /dev/null
+++ b/SOURCES/BZ_2149048-ip-Preserve-the-IP-address-order-when-applying.patch
@@ -0,0 +1,64 @@
+From 2d0cfd5ad8e049f30cad10d977a5fae8bc4e6b64 Mon Sep 17 00:00:00 2001
+From: Gris Ge <fge@redhat.com>
+Date: Thu, 10 Nov 2022 15:51:25 +0800
+Subject: [PATCH] ip: Preserve the IP address order when applying
+
+When applying the IP address, we should preserve the order for use case
+whether user is expecting non-first ones been set with `secondary` flag.
+
+In RHEL/CentOS 8, NetworkManager is using reverted IPv6 address
+according to
+https://bugzilla.redhat.com/show_bug.cgi?id=2139443
+
+Hence downstream nmstate will ship additional patch to fix it.
+The upstream nmstate will not revert the IPv6 address list before
+sending to NM.
+
+The downstream build of RHEL 8 has different behaviour than copr build
+from git main branch. It is hard to tell whether we are using downstream
+build or git build at runtime, hence we ship the
+`test_preserve_ipv6_addresses_order` test in RHEL 8.
+
+Integration test case included.
+
+Signed-off-by: Gris Ge <fge@redhat.com>
+---
+ libnmstate/ifaces/base_iface.py             |  4 +-
+ tests/integration/static_ip_address_test.py | 67 ++++++++++++++++++++-
+ tests/integration/testlib/env.py            |  5 ++
+ tests/integration/testlib/iproutelib.py     | 14 +++++
+ tests/lib/ifaces/ip_state_test.py           |  2 +
+ 5 files changed, 89 insertions(+), 3 deletions(-)
+
+diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py
+index fb2b7bb6..f29f9ac9 100644
+--- a/libnmstate/ifaces/base_iface.py
++++ b/libnmstate/ifaces/base_iface.py
+@@ -47,7 +47,6 @@ class IPState:
+         self._family = family
+         self._info = info
+         self._remove_stack_if_disabled()
+-        self._sort_addresses()
+         self._canonicalize_ip_addr()
+         self._canonicalize_dynamic()
+ 
+@@ -71,7 +70,7 @@ class IPState:
+                 addr[InterfaceIP.ADDRESS_IP]
+             )
+ 
+-    def _sort_addresses(self):
++    def sort_addresses(self):
+         self.addresses.sort(key=itemgetter(InterfaceIP.ADDRESS_IP))
+ 
+     def _remove_stack_if_disabled(self):
+@@ -431,6 +430,7 @@ class BaseIface:
+         self.sort_port()
+         for family in (Interface.IPV4, Interface.IPV6):
+             ip_state = self.ip_state(family)
++            ip_state.sort_addresses()
+             ip_state.remove_link_local_address()
+             self._info[family] = ip_state.to_dict()
+         state = self.to_dict()
+-- 
+2.38.1
+
diff --git a/SOURCES/BZ_2149048-nm-revert-IPv6-order-before-adding-them-to-setting.patch b/SOURCES/BZ_2149048-nm-revert-IPv6-order-before-adding-them-to-setting.patch
new file mode 100644
index 0000000..6b66195
--- /dev/null
+++ b/SOURCES/BZ_2149048-nm-revert-IPv6-order-before-adding-them-to-setting.patch
@@ -0,0 +1,31 @@
+From 08bf57af942e31a30f7f2c99c6238a3b662cc450 Mon Sep 17 00:00:00 2001
+From: Fernando Fernandez Mancera <ffmancera@riseup.net>
+Date: Tue, 29 Nov 2022 22:53:53 +0100
+Subject: [PATCH] nm: revert IPv6 order before adding them to setting
+
+This is a downstream patch that needs to be applied before any other
+patch. Please check:
+
+https://github.com/nmstate/nmstate/commit/2d0cfd5ad8e049f30cad10d977a5fae8bc4e6b64
+
+Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
+---
+ libnmstate/nm/ipv6.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libnmstate/nm/ipv6.py b/libnmstate/nm/ipv6.py
+index 71a80823..27ecf150 100644
+--- a/libnmstate/nm/ipv6.py
++++ b/libnmstate/nm/ipv6.py
+@@ -174,7 +174,7 @@ def _set_dynamic(setting_ip, is_dhcp, is_autoconf):
+ 
+ 
+ def _set_static(setting_ip, ip_addresses):
+-    for address in ip_addresses:
++    for address in reversed(ip_addresses):
+         if iplib.is_ipv6_link_local_addr(
+             address[InterfaceIPv6.ADDRESS_IP],
+             address[InterfaceIPv6.ADDRESS_PREFIX_LENGTH],
+-- 
+2.38.1
+
diff --git a/SOURCES/BZ_2150705-nm-fix-activation-retry.patch b/SOURCES/BZ_2150705-nm-fix-activation-retry.patch
new file mode 100644
index 0000000..b400490
--- /dev/null
+++ b/SOURCES/BZ_2150705-nm-fix-activation-retry.patch
@@ -0,0 +1,151 @@
+From 2a98b06c70c93c63298ac0cc5402a74d8015f40b Mon Sep 17 00:00:00 2001
+From: Gris Ge <fge@redhat.com>
+Date: Tue, 29 Nov 2022 12:57:19 +0800
+Subject: [PATCH 1/2] nm: Fix activation retry
+
+Using `time.sleep(5)` will not process the MainLoop of NM library which
+will cause checkpoint expire during `time.sleep()`.
+
+Use Glib timer will fix this problem.
+
+Integration test case created to create 32 veth in single transaction,
+the test case is marked as slow as it takes 10 seconds to finish.
+
+Signed-off-by: Gris Ge <fge@redhat.com>
+---
+ libnmstate/nm/active_connection.py | 38 +++++++++++++++++-------------
+ 1 file changed, 22 insertions(+), 16 deletions(-)
+
+diff --git a/libnmstate/nm/active_connection.py b/libnmstate/nm/active_connection.py
+index 66e82aec..4c0ef9d5 100644
+--- a/libnmstate/nm/active_connection.py
++++ b/libnmstate/nm/active_connection.py
+@@ -1,5 +1,5 @@
+ #
+-# Copyright (c) 2019-2020 Red Hat, Inc.
++# Copyright (c) 2019-2022 Red Hat, Inc.
+ #
+ # This file is part of nmstate
+ #
+@@ -17,7 +17,6 @@
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
+ #
+ 
+-import time
+ import logging
+ 
+ from libnmstate.error import NmstateLibnmError
+@@ -105,6 +104,19 @@ class ProfileActivation:
+         self._fallback_checker = None
+         self._fallback_checker_counter = 0
+ 
++    def _retry_activate(self, _user_data):
++        specific_object = None
++        retried = True
++        self._ctx.client.activate_connection_async(
++            self._nm_profile,
++            self._nm_dev,
++            specific_object,
++            self._ctx.cancellable,
++            self._activate_profile_callback,
++            retried,
++        )
++        return GLib.SOURCE_REMOVE
++
+     def run(self):
+         specific_object = None
+         self._action = (
+@@ -112,7 +124,7 @@ class ProfileActivation:
+             f"iface:{self._iface_name} type: {self._iface_type}"
+         )
+ 
+-        retry = True
++        retried = False
+         self._ctx.register_async(self._action)
+         self._ctx.client.activate_connection_async(
+             self._nm_profile,
+@@ -120,7 +132,7 @@ class ProfileActivation:
+             specific_object,
+             self._ctx.cancellable,
+             self._activate_profile_callback,
+-            retry,
++            retried,
+         )
+         self._fallback_checker = GLib.timeout_source_new(
+             FALLBACK_CHECKER_INTERNAL * 1000
+@@ -154,7 +166,7 @@ class ProfileActivation:
+         activation._fallback_checker.attach(ctx.context)
+         activation._wait_profile_activation()
+ 
+-    def _activate_profile_callback(self, nm_client, result, retry):
++    def _activate_profile_callback(self, nm_client, result, retried):
+         nm_ac = None
+         if self._ctx.is_cancelled():
+             self._activation_clean_up()
+@@ -162,22 +174,16 @@ class ProfileActivation:
+         try:
+             nm_ac = nm_client.activate_connection_finish(result)
+         except GLib.Error as e:
+-            if retry:
+-                retry = False
+-                specific_object = None
++            if not retried:
+                 logging.debug(
+                     f"Action {self._action} failed, trying again in "
+                     f"{ACTIVATION_RETRY_SLEEP} seconds."
+                 )
+-                time.sleep(ACTIVATION_RETRY_SLEEP)
+-                self._ctx.client.activate_connection_async(
+-                    self._nm_profile,
+-                    self._nm_dev,
+-                    specific_object,
+-                    self._ctx.cancellable,
+-                    self._activate_profile_callback,
+-                    retry,
++                activation_retry_timer = GLib.timeout_source_new(
++                    ACTIVATION_RETRY_SLEEP * 1000
+                 )
++                activation_retry_timer.set_callback(self._retry_activate, None)
++                activation_retry_timer.attach(self._ctx.context)
+                 return
+             elif e.matches(Gio.io_error_quark(), Gio.IOErrorEnum.TIMED_OUT):
+                 logging.debug(
+-- 
+2.38.1
+
+
+From 70c4a665aa6341c8bf22e2a91749bd8ae551b2b7 Mon Sep 17 00:00:00 2001
+From: Gris Ge <fge@redhat.com>
+Date: Tue, 6 Dec 2022 16:12:21 +0800
+Subject: [PATCH 2/2] nm: Fix `time.sleep()` in `_import_current_device()`
+
+The `time.sleep()` in `_import_current_device()` will cause checkpoint
+timeout as the `time.sleep()` does not iterate the NM Mainloop which
+cause the checkpoint refresh not function as expected.
+
+Invoking a `NmContext.refresh()` after every small `time.sleep()` fixed
+this problem.
+
+Extra test case not required, this problem only found on slow server(my
+VM compiling rust project at the same time).
+
+Signed-off-by: Gris Ge <fge@redhat.com>
+---
+ libnmstate/nm/profile.py | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/libnmstate/nm/profile.py b/libnmstate/nm/profile.py
+index 82643d73..85c0e623 100644
+--- a/libnmstate/nm/profile.py
++++ b/libnmstate/nm/profile.py
+@@ -501,6 +501,7 @@ class NmProfile:
+                 break
+             else:
+                 time.sleep(IMPORT_NM_DEV_RETRY_INTERNAL)
++                self._ctx.refresh()
+ 
+     def import_current(self):
+         self._nm_dev = get_nm_dev(
+-- 
+2.38.1
+
diff --git a/SPECS/nmstate.spec b/SPECS/nmstate.spec
index 64e4c0c..a29ece7 100644
--- a/SPECS/nmstate.spec
+++ b/SPECS/nmstate.spec
@@ -4,7 +4,7 @@
 
 Name:           nmstate
 Version:        1.3.3
-Release:        1%{?dist}
+Release:        4%{?dist}
 Summary:        Declarative network manager API
 License:        LGPLv2+
 URL:            https://github.com/%{srcname}/%{srcname}
@@ -12,6 +12,12 @@ Source0:        %{url}/releases/download/v%{version}/%{srcname}-%{version}.tar.g
 Source1:        %{url}/releases/download/v%{version}/%{srcname}-%{version}.tar.gz.asc
 Source2:        https://www.nmstate.io/nmstate.gpg
 Source3:        %{url}/releases/download/v%{version}/%{srcname}-vendor-%{version}.tar.xz
+Patch0:         BZ_2149048-nm-revert-IPv6-order-before-adding-them-to-setting.patch
+# Patches 0X are reserved for downstream only patches
+Patch10:        BZ_2139698-nm-sriov-Do-not-touch-SR-IOV-if-not-desired.patch
+Patch11:        BZ_2128555-ip-allow-extra-IP-address-found-in-verification-stag.patch
+Patch12:        BZ_2149048-ip-Preserve-the-IP-address-order-when-applying.patch
+Patch13:        BZ_2150705-nm-fix-activation-retry.patch
 BuildRequires:  python3-devel
 BuildRequires:  python3-setuptools
 BuildRequires:  gnupg2
@@ -146,6 +152,16 @@ popd
 /sbin/ldconfig
 
 %changelog
+* Tue Dec 06 2022 Gris Ge <fge@redhat.com> - 1.3.3-4
+- Fix activation retry. RHBZ#2150705
+
+* Tue Nov 29 2022 Fernando Fernandez Mancera <ferferna@redhat.com> - 1.3.3-3
+- Revert IPv6 addresses order before adding them to IP setting. RHBZ#2149048
+
+* Sat Nov 12 2022 Fernando Fernandez Mancera <ferferna@redhat.com> - 1.3.3-2
+- Do not remove SR-IOV that is not in desired state. RHBZ#2139698
+- Allow extra IP addresses found in verification stage. RHBZ#2128555
+
 * Mon Aug 15 2022 Gris Ge <fge@redhat.com> - 1.3.3-1
 - Upgrade to nmstate-1.3.3