linux一次ip和默认网关丢失
最近排查一个和网络相关的问题,学习到了一些 dhcp 和 systemd-networkd 的一些知识,在这里记录分享一下
0x1 问题
某日我们对一个机器做流量压测,然后机器负载拉满,ip无法访问,然后出现了再也无法通过ip访问的情况,ping也是不通的
0x2 排查
机器ip不见了?
ping不通,说明机器没有和ip绑定,进入机器后台(我们的场景是虚拟机,所以有管理平台进入后台)
进入后台,执行 ip a 命令,大致如下
1 | eth0: .... |
一个很关键的问题在于,没有ip地址,正常如下:
1 | 2: enp9s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 |
再通过ip r
查看网关,如下
1 | 172.17.0.0/16 .... |
发现没有default网关的路由,可能有其他的一些虚拟网卡网桥的东西,比如docker创建的之类的
说明系统的网络服务出现了问题,没有自动去获取dhcp 的ip,或者静态ip服务也没有设置正常,那么就继续排查网络服务
systemd-networkd 服务
linux常见管理网络的方式有三种
network服务
systemd-networkd 服务
NetworkManager 服务
这三者都可以通过systemd来管理
第一种是最初直接设置网卡的方式,它实际上就是个脚本,每次开机自动配置一下网卡,通过dhcp或者静态ip的方式,如果是dhcp后续就会自动续约之类的
第二种就是systemd自带的网路管理,也是通过一个配置文件来处理,它通常会有后台服务,定期获取dhcp的状态并处理,其实和network没有太大差别
第三种其实主要是附加了一些自动化的功能,常见于桌面端,因为提供了一些图形化界面,并且会自动发现网卡并配置,服务端用的比较少
这里的服务其实是采用了第一种的静态ip和第二种的dhcp混合的方式
首先查看 systemd-networkd 服务日志:
1 | eth0: DHCP Addrees set failed: connect timeout |
最主要的就是这两条,能的到的信息如下:
systemd-networkd 在这个时候dhcp租约到期了,需要重新申请IP,但是访问 dhcp 服务器超时了
systemd-networkd 不会再去处理关于 eth0 网卡的配置了
此外,我们在 /etc/sysconfig/network-scripts/ifcfg-eth0
能看到静态ip的配置,说明这个系统同时启用了 network 服务来配置静态ip,但是这个静态ip只会配置一次,即系统启动之时
由于内部特殊组件的原因,这里不方便展开说,最终我们定位这时候的ip和网关丢失与该服务无关
那么为什么systemd-networkd在超时之后为什么会清除网卡ip和默认网关呢?
查源码是一个很烦的事情,我们更希望从其他的特征中发现这个问题
ip会自动清除?
再仔细观察我们的 ip a 的输出,会发现它有一个很特殊的行
这是啥,好像超出理解范围了,通过文心一言的问答,如下
valid_lft 代表这个 IP 的可使用时长
preferred_lft 代表这个 IP 的优先使用时长
简单理解,就是第一个时间代表了这个ip可以用多久,第二个代表了这个ip在多久之内是优先使用的
这好像就对上了,它会自动清除
实验一下,将时间调整为 10s 和 5s
1 | ip a change dev enp0s3 10.0.2.6/24 valid_lft 10 preferred_lft 5 |
得到如下结果:
时间流逝
ip 自动丢失,默认网关路由也消失,也就验证了我们的猜想
恢复ip
只需要重启 systemd-networkd 服务即可
0x3 收获
实际上整个问题非常简单,难点在于
对这几个组件一无所知,Linux下的网络管理方式和配置方式
DHCP又是怎么实现的
IP竟然还有有效期会自动消失
事实上DHCP这里我没有展开讲,因为中间我忽略了踩坑的过程,开始我试图复现错误日志中的超时问题,利用iptables对 dhcp 的 67 和 68 端口做丢包处理,结果我意外的发现,systemd-networkd这个服务竟然还能正确获取到ip地址,这一点真的很神奇,可能需要进一步了解其工作原理
DHCP
DHCP的服务过程大概如下:
客户端发起一个广播,找dhcp服务器
dhcp服务器收到请求,知道了对方的mac地址,然后尝试提供一个ip地址和网关信息,并继续广播一个分配的请求
客户端收到广播后确认这个ip可以,就继续广播一个请求说自己收到了并且需要使用这个
服务端收到这个广播之后继续广播一个请求,ACK确认
然后有个特殊点在于,在租期的 0.5 和 0.875 节点时,客户端会尝试续约,但是这个时候是单播的,为什么前面全部用广播是因为客户端没有一个分配好的ip地址
大家其实会有一个讨论点在于dhcp服务端第一次分配ip的时候是广播还是单播,这里我实测抓包了一下,从目的ip的角度来说,确实全部为广播,因为在网络中可能有多个dhcp服务器回包,客户端会选择第一个接受到的,然后广播说自己选择了哪一个,从逻辑上讲,没有完成整个过程之前,这个客户端都是没有自己的ip的,所以就应该使用广播