diff options
author | Waleed Mousa <32266980+wmousa@users.noreply.github.com> | 2023-03-22 18:45:33 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-22 10:45:33 -0600 |
commit | 7f91bdea4c684fb0ae12489751a1343261a9ca93 (patch) | |
tree | 7e2551add9751ebe7061b61571636d694d810d6f | |
parent | 85b2fbc2a811d6efb703284bea93b35c5cdd4135 (diff) | |
download | cloud-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__.py | 4 | ||||
-rw-r--r-- | cloudinit/net/dhcp.py | 24 | ||||
-rw-r--r-- | tests/unittests/net/test_dhcp.py | 103 | ||||
-rw-r--r-- | tools/.github-cla-signers | 1 |
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 |