From 4610833d1e9a0839321f84bbc3c8d27ff19a17f2 Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
Date: Thu, 2 Feb 2023 10:13:08 -0600
Subject: [PATCH] Ignore duplicate macs from mscc_felix and fsl_enetc

Reference:https://github.com/canonical/cloud-init/commit/4610833d1e9a0839321f84bbc3c8d27ff19a17f2
Conflict:import does_not_raise diffs.

mscc_felix and fsl_enetc are drivers representing a switch that is
expected to have duplicate macs. If we encounter either of these
drivers, we should not raise the duplicate mac exception.

LP: #1997922
---
 cloudinit/net/__init__.py   | 16 ++++++++++++++++
 tests/unittests/test_net.py | 20 ++++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py
index 96ce6f5..a308c98 100644
--- a/cloudinit/net/__init__.py
+++ b/cloudinit/net/__init__.py
@@ -929,6 +929,22 @@ def get_interfaces_by_mac_on_linux(blacklist_drivers=None) -> dict:
                         % (ret[mac], driver_map[mac], name)
                     )
 
+            # This is intended to be a short-term fix of LP: #1997922
+            # Long term, we should better handle configuration of virtual
+            # devices where duplicate MACs are expected early in boot if
+            # cloud-init happens to enumerate network interfaces before drivers
+            # have fully initialized the leader/subordinate relationships for
+            # those devices or switches.
+            if driver == "mscc_felix" or driver == "fsl_enetc":
+                LOG.debug(
+                    "Ignoring duplicate macs from '%s' and '%s' due to "
+                    "driver '%s'.",
+                    name,
+                    ret[mac],
+                    driver,
+                )
+                continue
+
             if raise_duplicate_mac_error:
                 raise RuntimeError(msg)
 
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index 0db4442..e5dd979 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -11,6 +11,7 @@ from cloudinit import temp_utils
 from cloudinit import subp
 from cloudinit import util
 from cloudinit import safeyaml as yaml
+from contextlib import ExitStack as does_not_raise
 
 from cloudinit.tests.helpers import (
     CiTestCase, FilesystemMockingTestCase, dir2dict, mock, populate_dir)
@@ -5515,6 +5516,7 @@ class TestInterfaceHasOwnMac(CiTestCase):
     mock.Mock(return_value=False)
 )
 class TestGetInterfacesByMac(CiTestCase):
+    with_logs = True
     _data = {'bonds': ['bond1'],
              'bridges': ['bridge1'],
              'vlans': ['bond1.101'],
@@ -5680,6 +5682,24 @@ class TestGetInterfacesByMac(CiTestCase):
                     ib_addr_eth_format: 'ib0', ib_addr: 'ib0'}
         self.assertEqual(expected, result)
 
+    def test_duplicate_ignored_macs(self):
+        # LP: #199792
+        self._data = copy.deepcopy(self._data)
+        self._data["macs"]["swp0"] = "9a:57:7d:78:47:c0"
+        self._data["macs"]["swp1"] = "9a:57:7d:78:47:c0"
+        self._data["own_macs"].append("swp0")
+        self._data["own_macs"].append("swp1")
+        self._data["drivers"]["swp0"] = "mscc_felix"
+        self._data["drivers"]["swp1"] = "mscc_felix"
+        self._mock_setup()
+        with does_not_raise():
+            net.get_interfaces_by_mac()
+        pattern = (
+            "Ignoring duplicate macs from 'swp[0-1]' and 'swp[0-1]' due to "
+            "driver 'mscc_felix'."
+        )
+        assert re.search(pattern, self.logs.getvalue())
+
 
 class TestInterfacesSorting(CiTestCase):
 
-- 
2.33.0


