diff --git a/SOURCES/ci-Fix-requiring-device-number-on-EC2-derivatives-836.patch b/SOURCES/ci-Fix-requiring-device-number-on-EC2-derivatives-836.patch
new file mode 100644
index 0000000..120a4f1
--- /dev/null
+++ b/SOURCES/ci-Fix-requiring-device-number-on-EC2-derivatives-836.patch
@@ -0,0 +1,103 @@
+From 93b48730e201bf374f75a3f71d8d6b28211016ba Mon Sep 17 00:00:00 2001
+From: Eduardo Otubo <otubo@redhat.com>
+Date: Tue, 23 Mar 2021 16:14:16 +0100
+Subject: [PATCH] Fix requiring device-number on EC2 derivatives (#836)
+
+RH-Author: Eduardo Otubo <otubo@redhat.com>
+RH-MergeRequest: 3: Fix requiring device-number on EC2 derivatives (#836)
+RH-Commit: [1/1] f372b10d179a969fcf824db8a39bdea3befc4ef4 (eterell/cloud-init)
+RH-Bugzilla: 1942699
+RH-Acked-by: Acked-by: Mohammed Gamal <mgamal@redhat.com>
+RH-Acked-by: Acked-by: Vitaly Kuznetsov vkuznets@redhat.com
+RH-Acked-by: Acked-by: Cathy Avery cavery@redhat.com
+
+commit 9bd19645a61586b82e86db6f518dd05c3363b17f
+Author: James Falcon <TheRealFalcon@users.noreply.github.com>
+Date:   Mon Mar 8 14:09:47 2021 -0600
+
+    Fix requiring device-number on EC2 derivatives (#836)
+
+    #342 (70dbccbb) introduced the ability to determine route-metrics based on
+    the `device-number` provided by the EC2 IMDS. Not all datasources that
+    subclass EC2 will have this attribute, so allow the old behavior if
+    `device-number` is not present.
+
+    LP: #1917875
+
+Signed-off-by: Eduardo Otubo <otubo@redhat.com>
+---
+ cloudinit/sources/DataSourceEc2.py            |  3 +-
+ .../unittests/test_datasource/test_aliyun.py  | 30 +++++++++++++++++++
+ 2 files changed, 32 insertions(+), 1 deletion(-)
+
+diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py
+index 1d09c12a..ce69d1b3 100644
+--- a/cloudinit/sources/DataSourceEc2.py
++++ b/cloudinit/sources/DataSourceEc2.py
+@@ -764,13 +764,14 @@ def convert_ec2_metadata_network_config(
+         netcfg['ethernets'][nic_name] = dev_config
+         return netcfg
+     # Apply network config for all nics and any secondary IPv4/v6 addresses
++    nic_idx = 0
+     for mac, nic_name in sorted(macs_to_nics.items()):
+         nic_metadata = macs_metadata.get(mac)
+         if not nic_metadata:
+             continue  # Not a physical nic represented in metadata
+         # device-number is zero-indexed, we want it 1-indexed for the
+         # multiplication on the following line
+-        nic_idx = int(nic_metadata['device-number']) + 1
++        nic_idx = int(nic_metadata.get('device-number', nic_idx)) + 1
+         dhcp_override = {'route-metric': nic_idx * 100}
+         dev_config = {'dhcp4': True, 'dhcp4-overrides': dhcp_override,
+                       'dhcp6': False,
+diff --git a/tests/unittests/test_datasource/test_aliyun.py b/tests/unittests/test_datasource/test_aliyun.py
+index b626229e..a57f86a1 100644
+--- a/tests/unittests/test_datasource/test_aliyun.py
++++ b/tests/unittests/test_datasource/test_aliyun.py
+@@ -7,6 +7,7 @@ from unittest import mock
+ 
+ from cloudinit import helpers
+ from cloudinit.sources import DataSourceAliYun as ay
++from cloudinit.sources.DataSourceEc2 import convert_ec2_metadata_network_config
+ from cloudinit.tests import helpers as test_helpers
+ 
+ DEFAULT_METADATA = {
+@@ -183,6 +184,35 @@ class TestAliYunDatasource(test_helpers.HttprettyTestCase):
+         self.assertEqual(ay.parse_public_keys(public_keys),
+                          public_keys['key-pair-0']['openssh-key'])
+ 
++    def test_route_metric_calculated_without_device_number(self):
++        """Test that route-metric code works without `device-number`
++
++        `device-number` is part of EC2 metadata, but not supported on aliyun.
++        Attempting to access it will raise a KeyError.
++
++        LP: #1917875
++        """
++        netcfg = convert_ec2_metadata_network_config(
++            {"interfaces": {"macs": {
++                "06:17:04:d7:26:09": {
++                    "interface-id": "eni-e44ef49e",
++                },
++                "06:17:04:d7:26:08": {
++                    "interface-id": "eni-e44ef49f",
++                }
++            }}},
++            macs_to_nics={
++                '06:17:04:d7:26:09': 'eth0',
++                '06:17:04:d7:26:08': 'eth1',
++            }
++        )
++
++        met0 = netcfg['ethernets']['eth0']['dhcp4-overrides']['route-metric']
++        met1 = netcfg['ethernets']['eth1']['dhcp4-overrides']['route-metric']
++
++        # route-metric numbers should be 100 apart
++        assert 100 == abs(met0 - met1)
++
+ 
+ class TestIsAliYun(test_helpers.CiTestCase):
+     ALIYUN_PRODUCT = 'Alibaba Cloud ECS'
+-- 
+2.27.0
+
diff --git a/SOURCES/ci-get_interfaces-don-t-exclude-Open-vSwitch-bridge-bon.patch b/SOURCES/ci-get_interfaces-don-t-exclude-Open-vSwitch-bridge-bon.patch
new file mode 100644
index 0000000..e9a0426
--- /dev/null
+++ b/SOURCES/ci-get_interfaces-don-t-exclude-Open-vSwitch-bridge-bon.patch
@@ -0,0 +1,150 @@
+From a0601a472dc5b05106617b35b81d8a0578ade339 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Lukas=20M=C3=A4rdian?= <luk@slyon.de>
+Date: Thu, 29 Oct 2020 14:38:56 +0100
+Subject: [PATCH 1/2] get_interfaces: don't exclude Open vSwitch bridge/bond
+ members (#608)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+RH-Author: Eduardo Otubo (otubo)
+RH-MergeRequest: 6: Patch series to fix "Bug 1957135 - Intermittent failure to start cloud-init due to failure to detect macs"
+RH-Commit: [1/2] 4362f855d2d1a250a7d18490b35e65a1133a00c2 (otubo/cloud-init)
+RH-Bugzilla: 1957135
+RH-Acked-by: Mohammed Gamal <mmorsy@redhat.com>
+RH-Acked-by: Emanuele Giuseppe Esposito <[eesposit@redhat.com](mailto:eesposit@redhat.com>
+
+commit 3c432b32de1bdce2699525201396a8bbc6a41f3e
+Author: Lukas Märdian <luk@slyon.de>
+Date:   Thu Oct 29 14:38:56 2020 +0100
+
+    get_interfaces: don't exclude Open vSwitch bridge/bond members (#608)
+
+    If an OVS bridge was used as the only/primary interface, the 'init'
+    stage failed with a "Not all expected physical devices present" error,
+    leaving the system with a broken SSH setup.
+
+    LP: #1898997
+
+Signed-off-by: Eduardo Otubo <otubo@redhat.com>
+---
+ cloudinit/net/__init__.py        | 15 +++++++++++--
+ cloudinit/net/tests/test_init.py | 36 +++++++++++++++++++++++++++++++-
+ tools/.github-cla-signers        |  1 +
+ 3 files changed, 49 insertions(+), 3 deletions(-)
+
+diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py
+index e233149a..0aa58b27 100644
+--- a/cloudinit/net/__init__.py
++++ b/cloudinit/net/__init__.py
+@@ -124,6 +124,15 @@ def master_is_bridge_or_bond(devname):
+     return (os.path.exists(bonding_path) or os.path.exists(bridge_path))
+ 
+ 
++def master_is_openvswitch(devname):
++    """Return a bool indicating if devname's master is openvswitch"""
++    master_path = get_master(devname)
++    if master_path is None:
++        return False
++    ovs_path = sys_dev_path(devname, path="upper_ovs-system")
++    return os.path.exists(ovs_path)
++
++
+ def is_netfailover(devname, driver=None):
+     """ netfailover driver uses 3 nics, master, primary and standby.
+         this returns True if the device is either the primary or standby
+@@ -855,8 +864,10 @@ def get_interfaces():
+             continue
+         if is_bond(name):
+             continue
+-        if get_master(name) is not None and not master_is_bridge_or_bond(name):
+-            continue
++        if get_master(name) is not None:
++            if (not master_is_bridge_or_bond(name) and
++                    not master_is_openvswitch(name)):
++                continue
+         if is_netfailover(name):
+             continue
+         mac = get_interface_mac(name)
+diff --git a/cloudinit/net/tests/test_init.py b/cloudinit/net/tests/test_init.py
+index 311ab6f8..0535387a 100644
+--- a/cloudinit/net/tests/test_init.py
++++ b/cloudinit/net/tests/test_init.py
+@@ -190,6 +190,28 @@ class TestReadSysNet(CiTestCase):
+         self.assertTrue(net.master_is_bridge_or_bond('eth1'))
+         self.assertTrue(net.master_is_bridge_or_bond('eth2'))
+ 
++    def test_master_is_openvswitch(self):
++        ovs_mac = 'bb:cc:aa:bb:cc:aa'
++
++        # No master => False
++        write_file(os.path.join(self.sysdir, 'eth1', 'address'), ovs_mac)
++
++        self.assertFalse(net.master_is_bridge_or_bond('eth1'))
++
++        # masters without ovs-system => False
++        write_file(os.path.join(self.sysdir, 'ovs-system', 'address'), ovs_mac)
++
++        os.symlink('../ovs-system', os.path.join(self.sysdir, 'eth1',
++                   'master'))
++
++        self.assertFalse(net.master_is_openvswitch('eth1'))
++
++        # masters with ovs-system => True
++        os.symlink('../ovs-system', os.path.join(self.sysdir, 'eth1',
++                   'upper_ovs-system'))
++
++        self.assertTrue(net.master_is_openvswitch('eth1'))
++
+     def test_is_vlan(self):
+         """is_vlan is True when /sys/net/devname/uevent has DEVTYPE=vlan."""
+         ensure_file(os.path.join(self.sysdir, 'eth0', 'uevent'))
+@@ -465,20 +487,32 @@ class TestGetInterfaceMAC(CiTestCase):
+     ):
+         bridge_mac = 'aa:bb:cc:aa:bb:cc'
+         bond_mac = 'cc:bb:aa:cc:bb:aa'
++        ovs_mac = 'bb:cc:aa:bb:cc:aa'
++
+         write_file(os.path.join(self.sysdir, 'br0', 'address'), bridge_mac)
+         write_file(os.path.join(self.sysdir, 'br0', 'bridge'), '')
+ 
+         write_file(os.path.join(self.sysdir, 'bond0', 'address'), bond_mac)
+         write_file(os.path.join(self.sysdir, 'bond0', 'bonding'), '')
+ 
++        write_file(os.path.join(self.sysdir, 'ovs-system', 'address'),
++                   ovs_mac)
++
+         write_file(os.path.join(self.sysdir, 'eth1', 'address'), bridge_mac)
+         os.symlink('../br0', os.path.join(self.sysdir, 'eth1', 'master'))
+ 
+         write_file(os.path.join(self.sysdir, 'eth2', 'address'), bond_mac)
+         os.symlink('../bond0', os.path.join(self.sysdir, 'eth2', 'master'))
+ 
++        write_file(os.path.join(self.sysdir, 'eth3', 'address'), ovs_mac)
++        os.symlink('../ovs-system', os.path.join(self.sysdir, 'eth3',
++                   'master'))
++        os.symlink('../ovs-system', os.path.join(self.sysdir, 'eth3',
++                   'upper_ovs-system'))
++
+         interface_names = [interface[0] for interface in net.get_interfaces()]
+-        self.assertEqual(['eth1', 'eth2'], sorted(interface_names))
++        self.assertEqual(['eth1', 'eth2', 'eth3', 'ovs-system'],
++                         sorted(interface_names))
+ 
+ 
+ class TestInterfaceHasOwnMAC(CiTestCase):
+diff --git a/tools/.github-cla-signers b/tools/.github-cla-signers
+index e5d2b95c..db55361a 100644
+--- a/tools/.github-cla-signers
++++ b/tools/.github-cla-signers
+@@ -16,6 +16,7 @@ matthewruffell
+ nishigori
+ omBratteng
+ onitake
++slyon
+ smoser
+ sshedi
+ TheRealFalcon
+-- 
+2.27.0
+
diff --git a/SOURCES/ci-net-exclude-OVS-internal-interfaces-in-get_interface.patch b/SOURCES/ci-net-exclude-OVS-internal-interfaces-in-get_interface.patch
new file mode 100644
index 0000000..7304f89
--- /dev/null
+++ b/SOURCES/ci-net-exclude-OVS-internal-interfaces-in-get_interface.patch
@@ -0,0 +1,512 @@
+From 83e17432645b9e959c82ffe9c86d20fa183bc5ef Mon Sep 17 00:00:00 2001
+From: Daniel Watkins <oddbloke@ubuntu.com>
+Date: Mon, 8 Mar 2021 12:50:57 -0500
+Subject: [PATCH 2/2] net: exclude OVS internal interfaces in get_interfaces
+ (#829)
+
+RH-Author: Eduardo Otubo (otubo)
+RH-MergeRequest: 6: Patch series to fix "Bug 1957135 - Intermittent failure to start cloud-init due to failure to detect macs"
+RH-Commit: [2/2] d401dc64a7ceeecb091a792aa24de334940a3750 (otubo/cloud-init)
+RH-Bugzilla: 1957135
+RH-Acked-by: Mohammed Gamal <mmorsy@redhat.com>
+RH-Acked-by: Emanuele Giuseppe Esposito <[eesposit@redhat.com](mailto:eesposit@redhat.com>
+
+commit 121bc04cdf0e6732fe143b7419131dc250c13384
+Author: Daniel Watkins <oddbloke@ubuntu.com>
+Date:   Mon Mar 8 12:50:57 2021 -0500
+
+    net: exclude OVS internal interfaces in get_interfaces (#829)
+
+    `get_interfaces` is used to in two ways, broadly: firstly, to determine
+    the available interfaces when converting cloud network configuration
+    formats to cloud-init's network configuration formats; and, secondly, to
+    ensure that any interfaces which are specified in network configuration
+    are (a) available, and (b) named correctly.  The first of these is
+    unaffected by this commit, as no clouds support Open vSwitch
+    configuration in their network configuration formats.
+
+    For the second, we check that MAC addresses of physical devices are
+    unique.  In some OVS configurations, there are OVS-created devices which
+    have duplicate MAC addresses, either with each other or with physical
+    devices.  As these interfaces are created by OVS, we can be confident
+    that (a) they will be available when appropriate, and (b) that OVS will
+    name them correctly.  As such, this commit excludes any OVS-internal
+    interfaces from the set of interfaces returned by `get_interfaces`.
+
+    LP: #1912844
+
+Signed-off-by: Eduardo Otubo <otubo@redhat.com>
+---
+ cloudinit/net/__init__.py                     |  62 +++++++++
+ cloudinit/net/tests/test_init.py              | 119 ++++++++++++++++++
+ .../sources/helpers/tests/test_openstack.py   |   5 +
+ cloudinit/sources/tests/test_oracle.py        |   4 +
+ .../integration_tests/bugs/test_lp1912844.py  | 103 +++++++++++++++
+ .../test_datasource/test_configdrive.py       |   8 ++
+ tests/unittests/test_net.py                   |  20 +++
+ 7 files changed, 321 insertions(+)
+ create mode 100644 tests/integration_tests/bugs/test_lp1912844.py
+
+diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py
+index 0aa58b27..2ff770e1 100644
+--- a/cloudinit/net/__init__.py
++++ b/cloudinit/net/__init__.py
+@@ -6,6 +6,7 @@
+ # This file is part of cloud-init. See LICENSE file for license information.
+ 
+ import errno
++import functools
+ import ipaddress
+ import logging
+ import os
+@@ -19,6 +20,19 @@ from cloudinit.url_helper import UrlError, readurl
+ LOG = logging.getLogger(__name__)
+ SYS_CLASS_NET = "/sys/class/net/"
+ DEFAULT_PRIMARY_INTERFACE = 'eth0'
++OVS_INTERNAL_INTERFACE_LOOKUP_CMD = [
++    "ovs-vsctl",
++    "--format",
++    "csv",
++    "--no-headings",
++    "--timeout",
++    "10",
++    "--columns",
++    "name",
++    "find",
++    "interface",
++    "type=internal",
++]
+ 
+ 
+ def natural_sort_key(s, _nsre=re.compile('([0-9]+)')):
+@@ -133,6 +147,52 @@ def master_is_openvswitch(devname):
+     return os.path.exists(ovs_path)
+ 
+ 
++@functools.lru_cache(maxsize=None)
++def openvswitch_is_installed() -> bool:
++    """Return a bool indicating if Open vSwitch is installed in the system."""
++    ret = bool(subp.which("ovs-vsctl"))
++    if not ret:
++        LOG.debug(
++            "ovs-vsctl not in PATH; not detecting Open vSwitch interfaces"
++        )
++    return ret
++
++
++@functools.lru_cache(maxsize=None)
++def get_ovs_internal_interfaces() -> list:
++    """Return a list of the names of OVS internal interfaces on the system.
++
++    These will all be strings, and are used to exclude OVS-specific interface
++    from cloud-init's network configuration handling.
++    """
++    try:
++        out, _err = subp.subp(OVS_INTERNAL_INTERFACE_LOOKUP_CMD)
++    except subp.ProcessExecutionError as exc:
++        if "database connection failed" in exc.stderr:
++            LOG.info(
++                "Open vSwitch is not yet up; no interfaces will be detected as"
++                " OVS-internal"
++            )
++            return []
++        raise
++    else:
++        return out.splitlines()
++
++
++def is_openvswitch_internal_interface(devname: str) -> bool:
++    """Returns True if this is an OVS internal interface.
++
++    If OVS is not installed or not yet running, this will return False.
++    """
++    if not openvswitch_is_installed():
++        return False
++    ovs_bridges = get_ovs_internal_interfaces()
++    if devname in ovs_bridges:
++        LOG.debug("Detected %s as an OVS interface", devname)
++        return True
++    return False
++
++
+ def is_netfailover(devname, driver=None):
+     """ netfailover driver uses 3 nics, master, primary and standby.
+         this returns True if the device is either the primary or standby
+@@ -877,6 +937,8 @@ def get_interfaces():
+         # skip nics that have no mac (00:00....)
+         if name != 'lo' and mac == zero_mac[:len(mac)]:
+             continue
++        if is_openvswitch_internal_interface(name):
++            continue
+         ret.append((name, mac, device_driver(name), device_devid(name)))
+     return ret
+ 
+diff --git a/cloudinit/net/tests/test_init.py b/cloudinit/net/tests/test_init.py
+index 0535387a..946f8ee2 100644
+--- a/cloudinit/net/tests/test_init.py
++++ b/cloudinit/net/tests/test_init.py
+@@ -391,6 +391,10 @@ class TestGetDeviceList(CiTestCase):
+         self.assertCountEqual(['eth0', 'eth1'], net.get_devicelist())
+ 
+ 
++@mock.patch(
++    "cloudinit.net.is_openvswitch_internal_interface",
++    mock.Mock(return_value=False),
++)
+ class TestGetInterfaceMAC(CiTestCase):
+ 
+     def setUp(self):
+@@ -1224,6 +1228,121 @@ class TestNetFailOver(CiTestCase):
+         self.assertFalse(net.is_netfailover(devname, driver))
+ 
+ 
++class TestOpenvswitchIsInstalled:
++    """Test cloudinit.net.openvswitch_is_installed.
++
++    Uses the ``clear_lru_cache`` local autouse fixture to allow us to test
++    despite the ``lru_cache`` decorator on the unit under test.
++    """
++
++    @pytest.fixture(autouse=True)
++    def clear_lru_cache(self):
++        net.openvswitch_is_installed.cache_clear()
++
++    @pytest.mark.parametrize(
++        "expected,which_return", [(True, "/some/path"), (False, None)]
++    )
++    @mock.patch("cloudinit.net.subp.which")
++    def test_mirrors_which_result(self, m_which, expected, which_return):
++        m_which.return_value = which_return
++        assert expected == net.openvswitch_is_installed()
++
++    @mock.patch("cloudinit.net.subp.which")
++    def test_only_calls_which_once(self, m_which):
++        net.openvswitch_is_installed()
++        net.openvswitch_is_installed()
++        assert 1 == m_which.call_count
++
++
++@mock.patch("cloudinit.net.subp.subp", return_value=("", ""))
++class TestGetOVSInternalInterfaces:
++    """Test cloudinit.net.get_ovs_internal_interfaces.
++
++    Uses the ``clear_lru_cache`` local autouse fixture to allow us to test
++    despite the ``lru_cache`` decorator on the unit under test.
++    """
++    @pytest.fixture(autouse=True)
++    def clear_lru_cache(self):
++        net.get_ovs_internal_interfaces.cache_clear()
++
++    def test_command_used(self, m_subp):
++        """Test we use the correct command when we call subp"""
++        net.get_ovs_internal_interfaces()
++
++        assert [
++            mock.call(net.OVS_INTERNAL_INTERFACE_LOOKUP_CMD)
++        ] == m_subp.call_args_list
++
++    def test_subp_contents_split_and_returned(self, m_subp):
++        """Test that the command output is appropriately mangled."""
++        stdout = "iface1\niface2\niface3\n"
++        m_subp.return_value = (stdout, "")
++
++        assert [
++            "iface1",
++            "iface2",
++            "iface3",
++        ] == net.get_ovs_internal_interfaces()
++
++    def test_database_connection_error_handled_gracefully(self, m_subp):
++        """Test that the error indicating OVS is down is handled gracefully."""
++        m_subp.side_effect = ProcessExecutionError(
++            stderr="database connection failed"
++        )
++
++        assert [] == net.get_ovs_internal_interfaces()
++
++    def test_other_errors_raised(self, m_subp):
++        """Test that only database connection errors are handled."""
++        m_subp.side_effect = ProcessExecutionError()
++
++        with pytest.raises(ProcessExecutionError):
++            net.get_ovs_internal_interfaces()
++
++    def test_only_runs_once(self, m_subp):
++        """Test that we cache the value."""
++        net.get_ovs_internal_interfaces()
++        net.get_ovs_internal_interfaces()
++
++        assert 1 == m_subp.call_count
++
++
++@mock.patch("cloudinit.net.get_ovs_internal_interfaces")
++@mock.patch("cloudinit.net.openvswitch_is_installed")
++class TestIsOpenVSwitchInternalInterface:
++    def test_false_if_ovs_not_installed(
++        self, m_openvswitch_is_installed, _m_get_ovs_internal_interfaces
++    ):
++        """Test that OVS' absence returns False."""
++        m_openvswitch_is_installed.return_value = False
++
++        assert not net.is_openvswitch_internal_interface("devname")
++
++    @pytest.mark.parametrize(
++        "detected_interfaces,devname,expected_return",
++        [
++            ([], "devname", False),
++            (["notdevname"], "devname", False),
++            (["devname"], "devname", True),
++            (["some", "other", "devices", "and", "ours"], "ours", True),
++        ],
++    )
++    def test_return_value_based_on_detected_interfaces(
++        self,
++        m_openvswitch_is_installed,
++        m_get_ovs_internal_interfaces,
++        detected_interfaces,
++        devname,
++        expected_return,
++    ):
++        """Test that the detected interfaces are used correctly."""
++        m_openvswitch_is_installed.return_value = True
++        m_get_ovs_internal_interfaces.return_value = detected_interfaces
++        assert expected_return == net.is_openvswitch_internal_interface(
++            devname
++        )
++
++
+ class TestIsIpAddress:
+     """Tests for net.is_ip_address.
+ 
+diff --git a/cloudinit/sources/helpers/tests/test_openstack.py b/cloudinit/sources/helpers/tests/test_openstack.py
+index 2bde1e3f..95fb9743 100644
+--- a/cloudinit/sources/helpers/tests/test_openstack.py
++++ b/cloudinit/sources/helpers/tests/test_openstack.py
+@@ -1,10 +1,15 @@
+ # This file is part of cloud-init. See LICENSE file for license information.
+ # ./cloudinit/sources/helpers/tests/test_openstack.py
++from unittest import mock
+ 
+ from cloudinit.sources.helpers import openstack
+ from cloudinit.tests import helpers as test_helpers
+ 
+ 
++@mock.patch(
++    "cloudinit.net.is_openvswitch_internal_interface",
++    mock.Mock(return_value=False)
++)
+ class TestConvertNetJson(test_helpers.CiTestCase):
+ 
+     def test_phy_types(self):
+diff --git a/cloudinit/sources/tests/test_oracle.py b/cloudinit/sources/tests/test_oracle.py
+index 7bd23813..902d1e40 100644
+--- a/cloudinit/sources/tests/test_oracle.py
++++ b/cloudinit/sources/tests/test_oracle.py
+@@ -173,6 +173,10 @@ class TestIsPlatformViable(test_helpers.CiTestCase):
+         m_read_dmi_data.assert_has_calls([mock.call('chassis-asset-tag')])
+ 
+ 
++@mock.patch(
++    "cloudinit.net.is_openvswitch_internal_interface",
++    mock.Mock(return_value=False)
++)
+ class TestNetworkConfigFromOpcImds:
+     def test_no_secondary_nics_does_not_mutate_input(self, oracle_ds):
+         oracle_ds._vnics_data = [{}]
+diff --git a/tests/integration_tests/bugs/test_lp1912844.py b/tests/integration_tests/bugs/test_lp1912844.py
+new file mode 100644
+index 00000000..efafae50
+--- /dev/null
++++ b/tests/integration_tests/bugs/test_lp1912844.py
+@@ -0,0 +1,103 @@
++"""Integration test for LP: #1912844
++
++cloud-init should ignore OVS-internal interfaces when performing its own
++interface determination: these interfaces are handled fully by OVS, so
++cloud-init should never need to touch them.
++
++This test is a semi-synthetic reproducer for the bug.  It uses a similar
++network configuration, tweaked slightly to DHCP in a way that will succeed even
++on "failed" boots.  The exact bug doesn't reproduce with the NoCloud
++datasource, because it runs at init-local time (whereas the MAAS datasource,
++from the report, runs only at init (network) time): this means that the
++networking code runs before OVS creates its interfaces (which happens after
++init-local but, of course, before networking is up), and so doesn't generate
++the traceback that they cause.  We work around this by calling
++``get_interfaces_by_mac` directly in the test code.
++"""
++import pytest
++
++from tests.integration_tests import random_mac_address
++
++MAC_ADDRESS = random_mac_address()
++
++NETWORK_CONFIG = """\
++bonds:
++    bond0:
++        interfaces:
++            - enp5s0
++        macaddress: {0}
++        mtu: 1500
++bridges:
++        ovs-br:
++            interfaces:
++            - bond0
++            macaddress: {0}
++            mtu: 1500
++            openvswitch: {{}}
++            dhcp4: true
++ethernets:
++    enp5s0:
++      mtu: 1500
++      set-name: enp5s0
++      match:
++          macaddress: {0}
++version: 2
++vlans:
++  ovs-br.100:
++    id: 100
++    link: ovs-br
++    mtu: 1500
++  ovs-br.200:
++    id: 200
++    link: ovs-br
++    mtu: 1500
++""".format(MAC_ADDRESS)
++
++
++SETUP_USER_DATA = """\
++#cloud-config
++packages:
++- openvswitch-switch
++"""
++
++
++@pytest.fixture
++def ovs_enabled_session_cloud(session_cloud):
++    """A session_cloud wrapper, to use an OVS-enabled image for tests.
++
++    This implementation is complicated by wanting to use ``session_cloud``s
++    snapshot cleanup/retention logic, to avoid having to reimplement that here.
++    """
++    old_snapshot_id = session_cloud.snapshot_id
++    with session_cloud.launch(
++        user_data=SETUP_USER_DATA,
++    ) as instance:
++        instance.instance.clean()
++        session_cloud.snapshot_id = instance.snapshot()
++
++    yield session_cloud
++
++    try:
++        session_cloud.delete_snapshot()
++    finally:
++        session_cloud.snapshot_id = old_snapshot_id
++
++
++@pytest.mark.lxd_vm
++def test_get_interfaces_by_mac_doesnt_traceback(ovs_enabled_session_cloud):
++    """Launch our OVS-enabled image and confirm the bug doesn't reproduce."""
++    launch_kwargs = {
++        "config_dict": {
++            "user.network-config": NETWORK_CONFIG,
++            "volatile.eth0.hwaddr": MAC_ADDRESS,
++        },
++    }
++    with ovs_enabled_session_cloud.launch(
++        launch_kwargs=launch_kwargs,
++    ) as client:
++        result = client.execute(
++            "python3 -c"
++            "'from cloudinit.net import get_interfaces_by_mac;"
++            "get_interfaces_by_mac()'"
++        )
++        assert result.ok
+diff --git a/tests/unittests/test_datasource/test_configdrive.py b/tests/unittests/test_datasource/test_configdrive.py
+index 6f830cc6..2e2b7847 100644
+--- a/tests/unittests/test_datasource/test_configdrive.py
++++ b/tests/unittests/test_datasource/test_configdrive.py
+@@ -494,6 +494,10 @@ class TestConfigDriveDataSource(CiTestCase):
+         self.assertEqual('config-disk (/dev/anything)', cfg_ds.subplatform)
+ 
+ 
++@mock.patch(
++    "cloudinit.net.is_openvswitch_internal_interface",
++    mock.Mock(return_value=False)
++)
+ class TestNetJson(CiTestCase):
+     def setUp(self):
+         super(TestNetJson, self).setUp()
+@@ -654,6 +658,10 @@ class TestNetJson(CiTestCase):
+             self.assertEqual(out_data, conv_data)
+ 
+ 
++@mock.patch(
++    "cloudinit.net.is_openvswitch_internal_interface",
++    mock.Mock(return_value=False)
++)
+ class TestConvertNetworkData(CiTestCase):
+ 
+     with_logs = True
+diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
+index 844d5ba8..3607c5e3 100644
+--- a/tests/unittests/test_net.py
++++ b/tests/unittests/test_net.py
+@@ -2825,6 +2825,10 @@ iface eth1 inet dhcp
+         self.assertEqual(0, mock_settle.call_count)
+ 
+ 
++@mock.patch(
++    "cloudinit.net.is_openvswitch_internal_interface",
++    mock.Mock(return_value=False)
++)
+ class TestRhelSysConfigRendering(CiTestCase):
+ 
+     with_logs = True
+@@ -3495,6 +3499,10 @@ USERCTL=no
+                 expected, self._render_and_read(network_config=v2data))
+ 
+ 
++@mock.patch(
++    "cloudinit.net.is_openvswitch_internal_interface",
++    mock.Mock(return_value=False)
++)
+ class TestOpenSuseSysConfigRendering(CiTestCase):
+ 
+     with_logs = True
+@@ -4859,6 +4867,10 @@ class TestNetRenderers(CiTestCase):
+             self.assertTrue(result)
+ 
+ 
++@mock.patch(
++    "cloudinit.net.is_openvswitch_internal_interface",
++    mock.Mock(return_value=False)
++)
+ class TestGetInterfaces(CiTestCase):
+     _data = {'bonds': ['bond1'],
+              'bridges': ['bridge1'],
+@@ -5008,6 +5020,10 @@ class TestInterfaceHasOwnMac(CiTestCase):
+         self.assertFalse(interface_has_own_mac("eth0"))
+ 
+ 
++@mock.patch(
++    "cloudinit.net.is_openvswitch_internal_interface",
++    mock.Mock(return_value=False)
++)
+ class TestGetInterfacesByMac(CiTestCase):
+     _data = {'bonds': ['bond1'],
+              'bridges': ['bridge1'],
+@@ -5164,6 +5180,10 @@ class TestInterfacesSorting(CiTestCase):
+             ['enp0s3', 'enp0s8', 'enp0s13', 'enp1s2', 'enp2s0', 'enp2s3'])
+ 
+ 
++@mock.patch(
++    "cloudinit.net.is_openvswitch_internal_interface",
++    mock.Mock(return_value=False)
++)
+ class TestGetIBHwaddrsByInterface(CiTestCase):
+ 
+     _ib_addr = '80:00:00:28:fe:80:00:00:00:00:00:00:00:11:22:03:00:33:44:56'
+-- 
+2.27.0
+
diff --git a/SPECS/cloud-init.spec b/SPECS/cloud-init.spec
index cedad04..da84b6e 100644
--- a/SPECS/cloud-init.spec
+++ b/SPECS/cloud-init.spec
@@ -6,7 +6,7 @@
 
 Name:           cloud-init
 Version:        20.3
-Release:        10%{?dist}
+Release:        10%{?dist}.3
 Summary:        Cloud instance init scripts
 
 Group:          System Environment/Base
@@ -40,6 +40,12 @@ Patch15: ci-DataSourceAzure-update-password-for-defuser-if-exist.patch
 Patch16: ci-Revert-ssh_util-handle-non-default-AuthorizedKeysFil.patch
 # For bz#1913127 - A typo in cloud-init man page
 Patch17: ci-fix-a-typo-in-man-page-cloud-init.1-752.patch
+# For bz#1942699 - [Aliyun][RHEL8.4][cloud-init] cloud-init service failed to start with Alibaba instance [rhel-8.4.0.z]
+Patch18: ci-Fix-requiring-device-number-on-EC2-derivatives-836.patch
+# For bz#1957135 - Intermittent failure to start cloud-init due to failure to detect macs [rhel-8.4.0.z]
+Patch19: ci-get_interfaces-don-t-exclude-Open-vSwitch-bridge-bon.patch
+# For bz#1957135 - Intermittent failure to start cloud-init due to failure to detect macs [rhel-8.4.0.z]
+Patch20: ci-net-exclude-OVS-internal-interfaces-in-get_interface.patch
 
 BuildArch:      noarch
 
@@ -231,6 +237,17 @@ fi
 %config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf
 
 %changelog
+* Thu May 13 2021 Miroslav Rezanina <mrezanin@redhat.com> - 20.3-10.el8_4.3
+- ci-get_interfaces-don-t-exclude-Open-vSwitch-bridge-bon.patch [bz#1957135]
+- ci-net-exclude-OVS-internal-interfaces-in-get_interface.patch [bz#1957135]
+- Resolves: bz#1957135
+  (Intermittent failure to start cloud-init due to failure to detect macs [rhel-8.4.0.z])
+
+* Tue Apr 06 2021 Miroslav Rezanina <mrezanin@redhat.com> - 20.3-10.el8_4.2
+- ci-Fix-requiring-device-number-on-EC2-derivatives-836.patch [bz#1942699]
+- Resolves: bz#1942699
+  ([Aliyun][RHEL8.4][cloud-init] cloud-init service failed to start with Alibaba instance [rhel-8.4.0.z])
+
 * Tue Feb 02 2021 Miroslav Rezanina <mrezanin@redhat.com> - 20.3-10.el8
 - ci-fix-a-typo-in-man-page-cloud-init.1-752.patch [bz#1913127]
 - Resolves: bz#1913127