summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWaleed Mousa <32266980+wmousa@users.noreply.github.com>2023-03-22 18:45:33 +0200
committerGitHub <noreply@github.com>2023-03-22 10:45:33 -0600
commit7f91bdea4c684fb0ae12489751a1343261a9ca93 (patch)
tree7e2551add9751ebe7061b61571636d694d810d6f
parent85b2fbc2a811d6efb703284bea93b35c5cdd4135 (diff)
downloadcloud-init-git-7f91bdea4c684fb0ae12489751a1343261a9ca93.tar.gz
Send dhcp-client-identifier for InfiniBand ports (#2043)
Sending dhclient command failed for InfiniBand ports because dhcp-client-identifier is not specified. So, providing this patch to allow send dhcp-client-identifier hardware with the dhclient command for InfiniBand ports. Signed-off-by: waleedm <waleedm@nvidia.com>
-rw-r--r--cloudinit/net/__init__.py4
-rw-r--r--cloudinit/net/dhcp.py24
-rw-r--r--tests/unittests/net/test_dhcp.py103
-rw-r--r--tools/.github-cla-signers1
4 files changed, 127 insertions, 5 deletions
diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py
index 244305d1..65d45edf 100644
--- a/cloudinit/net/__init__.py
+++ b/cloudinit/net/__init__.py
@@ -167,6 +167,10 @@ def master_is_openvswitch(devname):
return os.path.exists(ovs_path)
+def is_ib_interface(devname):
+ return read_sys_net_safe(devname, "type") == "32"
+
+
@functools.lru_cache(maxsize=None)
def openvswitch_is_installed() -> bool:
"""Return a bool indicating if Open vSwitch is installed in the system."""
diff --git a/cloudinit/net/dhcp.py b/cloudinit/net/dhcp.py
index 661b9848..a8949ebc 100644
--- a/cloudinit/net/dhcp.py
+++ b/cloudinit/net/dhcp.py
@@ -14,8 +14,13 @@ from io import StringIO
import configobj
-from cloudinit import subp, util
-from cloudinit.net import find_fallback_nic, get_devicelist
+from cloudinit import subp, temp_utils, util
+from cloudinit.net import (
+ find_fallback_nic,
+ get_devicelist,
+ get_interface_mac,
+ is_ib_interface,
+)
LOG = logging.getLogger(__name__)
@@ -136,6 +141,9 @@ def dhcp_discovery(dhclient_cmd_path, interface, dhcp_log_func=None):
# link up before attempting discovery. Since we are using -sf /bin/true,
# we need to do that "link up" ourselves first.
subp.subp(["ip", "link", "set", "dev", interface, "up"], capture=True)
+ # For INFINIBAND port the dhlient must be sent with dhcp-client-identifier.
+ # So here we are checking if the interface is INFINIBAND or not.
+ # If yes, we are generating the the client-id to be used with the dhclient
cmd = [
dhclient_cmd_path,
"-1",
@@ -148,6 +156,18 @@ def dhcp_discovery(dhclient_cmd_path, interface, dhcp_log_func=None):
"-sf",
"/bin/true",
]
+ if is_ib_interface(interface):
+ dhcp_client_identifier = "20:%s" % get_interface_mac(interface)[36:]
+ interface_dhclient_content = (
+ 'interface "%s" '
+ "{send dhcp-client-identifier %s;}"
+ % (interface, dhcp_client_identifier)
+ )
+ tmp_dir = temp_utils.get_tmp_ancestor(needs_exe=True)
+ file_name = os.path.join(tmp_dir, interface + "-dhclient.conf")
+ util.write_file(file_name, interface_dhclient_content)
+ cmd.append("-cf")
+ cmd.append(file_name)
out, err = subp.subp(cmd, capture=True)
# Wait for pid file and lease file to appear, and for the process
diff --git a/tests/unittests/net/test_dhcp.py b/tests/unittests/net/test_dhcp.py
index 40340553..2b680e1f 100644
--- a/tests/unittests/net/test_dhcp.py
+++ b/tests/unittests/net/test_dhcp.py
@@ -221,7 +221,6 @@ class TestDHCPRFC3442(CiTestCase):
class TestDHCPParseStaticRoutes(CiTestCase):
-
with_logs = True
def parse_static_routes_empty_string(self):
@@ -336,6 +335,7 @@ class TestDHCPParseStaticRoutes(CiTestCase):
class TestDHCPDiscoveryClean(CiTestCase):
with_logs = True
+ ib_address_prefix = "00:00:00:00:00:00:00:00:00:00:00:00"
@mock.patch("cloudinit.net.dhcp.find_fallback_nic")
def test_no_fallback_nic_found(self, m_fallback_nic):
@@ -450,12 +450,21 @@ class TestDHCPDiscoveryClean(CiTestCase):
)
m_kill.assert_not_called()
+ @mock.patch("cloudinit.net.dhcp.is_ib_interface", return_value=False)
@mock.patch("cloudinit.net.dhcp.os.remove")
@mock.patch("cloudinit.net.dhcp.util.get_proc_ppid")
@mock.patch("cloudinit.net.dhcp.os.kill")
@mock.patch("cloudinit.net.dhcp.subp.subp")
@mock.patch("cloudinit.util.wait_for_files", return_value=False)
- def test_dhcp_discovery(self, m_wait, m_subp, m_kill, m_getppid, m_remove):
+ def test_dhcp_discovery(
+ self,
+ m_wait,
+ m_subp,
+ m_kill,
+ m_getppid,
+ m_remove,
+ mocked_is_ib_interface,
+ ):
"""dhcp_discovery brings up the interface and runs dhclient.
It also returns the parsed dhcp.leases file.
@@ -512,6 +521,95 @@ class TestDHCPDiscoveryClean(CiTestCase):
]
)
m_kill.assert_has_calls([mock.call(my_pid, signal.SIGKILL)])
+ mocked_is_ib_interface.assert_called_once_with("eth9")
+
+ @mock.patch("cloudinit.temp_utils.get_tmp_ancestor", return_value="/tmp")
+ @mock.patch("cloudinit.util.write_file")
+ @mock.patch(
+ "cloudinit.net.dhcp.get_interface_mac",
+ return_value="%s:AA:AA:AA:00:00:AA:AA:AA" % ib_address_prefix,
+ )
+ @mock.patch("cloudinit.net.dhcp.is_ib_interface", return_value=True)
+ @mock.patch("cloudinit.net.dhcp.os.remove")
+ @mock.patch("cloudinit.net.dhcp.util.get_proc_ppid", return_value=1)
+ @mock.patch("cloudinit.net.dhcp.os.kill")
+ @mock.patch("cloudinit.net.dhcp.subp.subp", return_value=("", ""))
+ @mock.patch("cloudinit.util.wait_for_files", return_value=False)
+ def test_dhcp_discovery_ib(
+ self,
+ m_wait,
+ m_subp,
+ m_kill,
+ m_getppid,
+ m_remove,
+ mocked_is_ib_interface,
+ get_interface_mac,
+ mocked_write_file,
+ mocked_get_tmp_ancestor,
+ ):
+ """dhcp_discovery brings up the interface and runs dhclient.
+
+ It also returns the parsed dhcp.leases file.
+ """
+ lease_content = dedent(
+ """
+ lease {
+ interface "ib0";
+ fixed-address 192.168.2.74;
+ option subnet-mask 255.255.255.0;
+ option routers 192.168.2.1;
+ }
+ """
+ )
+ my_pid = 1
+ with mock.patch(
+ "cloudinit.util.load_file", side_effect=["1", lease_content]
+ ):
+ self.assertCountEqual(
+ [
+ {
+ "interface": "ib0",
+ "fixed-address": "192.168.2.74",
+ "subnet-mask": "255.255.255.0",
+ "routers": "192.168.2.1",
+ }
+ ],
+ dhcp_discovery("/sbin/dhclient", "ib0"),
+ )
+ # Interface was brought up before dhclient called
+ m_subp.assert_has_calls(
+ [
+ mock.call(
+ ["ip", "link", "set", "dev", "ib0", "up"], capture=True
+ ),
+ mock.call(
+ [
+ DHCLIENT,
+ "-1",
+ "-v",
+ "-lf",
+ LEASE_F,
+ "-pf",
+ PID_F,
+ "ib0",
+ "-sf",
+ "/bin/true",
+ "-cf",
+ "/tmp/ib0-dhclient.conf",
+ ],
+ capture=True,
+ ),
+ ]
+ )
+ m_kill.assert_has_calls([mock.call(my_pid, signal.SIGKILL)])
+ mocked_is_ib_interface.assert_called_once_with("ib0")
+ get_interface_mac.assert_called_once_with("ib0")
+ mocked_get_tmp_ancestor.assert_called_once_with(needs_exe=True)
+ mocked_write_file.assert_called_once_with(
+ "/tmp/ib0-dhclient.conf",
+ 'interface "ib0" {send dhcp-client-identifier '
+ "20:AA:AA:AA:00:00:AA:AA:AA;}",
+ )
@mock.patch("cloudinit.net.dhcp.os.remove")
@mock.patch("cloudinit.net.dhcp.util.get_proc_ppid")
@@ -552,7 +650,6 @@ class TestDHCPDiscoveryClean(CiTestCase):
class TestSystemdParseLeases(CiTestCase):
-
lxd_lease = dedent(
"""\
# This is private data. Do not parse.
diff --git a/tools/.github-cla-signers b/tools/.github-cla-signers
index 5ca63e76..19f91d6f 100644
--- a/tools/.github-cla-signers
+++ b/tools/.github-cla-signers
@@ -137,6 +137,7 @@ vteratipally
Vultaire
WebSpider
Wind-net
+wmousa
wschoot
wynnfeng
xiachen-rh