NetworkManager (接下来下面将简称 nm) 的 [main]
配置块中,可以选择不同的几种 DHCP Client 实现:
- dhclient
- dhcpcd
- internal
配置未指定的情况下默认使用 internal
,而前面 2 种都需要额外安装二进制:
Client | Distro / OS family | Package |
---|---|---|
dhclient |
C9S (CentOS Stream 9) | dhcp-client |
dhclient |
Debian | isc-dhcp-client |
dhcpcd |
C9S (CentOS Stream 9) | dhcpcd |
dhcpcd |
Debian 12 | dhcpcd |
dhcpcd |
Ubuntu 22 | dhcpcd5 |
internal
不依赖任何外部二进制,因为它是 nm 自己内部代码实现的。也就意味着在系统中不会存在由 nm fork 出的其他 DHCP Client 进程。
但是这个实现的具体情况有一个隐藏的秘密。如果你有幸使用 debug 输出对 nm 进行过调试,就可以在 DHCP 环节通过日志输出发现这个秘密:internal 有两个别名,systemd,或者 libsystemd。
是的,实际上,这些代码是来自于 systemd,对应 nm 的源代码目录中的 README 也指明了这点。
以 nm 的 DHCPv6 功能来说,对应 systemd 的代码可以追溯至 sd-dhcp6-client.c
通过 src/libnm-systemd-shared/README.md 的说明,可以看见 systemd 的对应代码是通过一种比较奇怪的工程实践导入进 nm 的 git 仓库的:从源仓库 clone 后再由脚本复制指定文件。由于我并没有 C++ 工程的实际经验,我也不好评价,但是对此最直观的感受就是:这让对应代码溯源变得较为困难,只能找到对应的 commit内容 才能知道上游 systemd 的代码具体对应关系。
正如文章最开始所展示的 man page 图中说的那样,internal
的实现不如其他外部实现的 featureful
。甚至可以说 systemd 的这些实现还存在很多的改进空间,与现实世界那些林林总总的 DHCP Server 实现稍微有点不兼容,有时会发生一些意想不到的问题。
比如这个 Issue: DHCPv6 client ignores packets with invalid bytes at the end,描述了在 Oracle 云上的基础设施中,其 VPC 网关实现的 DHCPv6 Reply
消息中尾部含有非法字节,被 systemd 认为是 bad msg
,导致 IPv6 的 DHCP 失败。
比较有意思的是,在 systemd PR 修正后,评论中有人反馈说 Oracle 在最初建议绕过这个问题(让客户不要使用 DHCP)后,在无法知晓的具体时间段悄悄完成了修复。
我为什么会挖掘并知道这些没用的知识?
因为我在华为云也碰见了类似的问题。一样是 IPv6 环境下的 DHCP 无法正常获取 IP,在对 nm 开启 debug 后同样看见了对 reply msg 判断为 bad msg 的信息。
就在我对 nm 的 DHCP 进行了上述情况的粗略挖掘,正准备进行下一步行动时,与同事闲聊了这个意外情况,然后就被其告知了华为云官网的文档链接,其中存在指出在 nm 的 DHCP 配置使用 dhclient 的明确指引段落。尝试了使用 dhclient 后一切正常。
所以,我个人的建议是,如果你也碰到了 nm 在 DHCP 场景下的问题,可以尝试配置使用 dhclient
。
或者尽量一开始就不用
internal
这个可能存在问题的代码实现,直到 Red Hat 某日在其未来的C10S
,C11S
中将默认的网络管理器设置为systemd-networkd
的那天。