pxe boot 多网卡dhcp fail 分析及修复详解

今天在调试linux启动的过程中发现 双网启动时候竟然只有一个网卡dhcp分配了ip

[2020-08-05 00:51:43.416382] root@atragon:~# ifconfig
[2020-08-05 00:51:44.167357] eth0      Link encap:Ethernet  HWaddr xxxxxxxxxx:40  
[2020-08-05 00:51:44.167357]            Scope:Link
[2020-08-05 00:51:44.167357]           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
[2020-08-05 00:51:44.167357]           RX packets:1280 errors:0 dropped:0 overruns:0 frame:0
[2020-08-05 00:51:44.167357]           TX packets:243 errors:0 dropped:0 overruns:0 carrier:0
[2020-08-05 00:51:44.167357]           collisions:0 txqueuelen:1000 
[2020-08-05 00:51:44.167357]           RX bytes:105878 (103.3 KiB)  TX bytes:16342 (15.9 KiB)
[2020-08-05 00:51:44.167357]           Interrupt:16 
[2020-08-05 00:51:44.167357] 
[2020-08-05 00:51:44.167357] eth1      Link encap:Ethernet  HWaddr xxxxxxxxx:41  
[2020-08-05 00:51:44.167357]           inet addr:192.168.1.84  Bcast:192.168.1.255  Mask:255.255.255.0
[2020-08-05 00:51:44.167357]            Scope:Link
[2020-08-05 00:51:44.167357]           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
[2020-08-05 00:51:44.167357]           RX packets:174908 errors:0 dropped:0 overruns:0 frame:0
[2020-08-05 00:51:44.167357]           TX packets:3893 errors:0 dropped:0 overruns:0 carrier:0
[2020-08-05 00:51:44.167357]           collisions:0 txqueuelen:1000 
[2020-08-05 00:51:44.167357]           RX bytes:259647682 (247.6 MiB)  TX bytes:251665 (245.7 KiB)
[2020-08-05 00:51:44.167357]           Interrupt:17

查看启动log发现 eth0 eth1 都发起了dhcp ,但是其中一个超时了,只有一个dhcp成功,发现重启很多次,现象仍然一样,下面我们来debug一下。

[2020-08-05 00:42:15.481503] IP-Config: eth1 hardware address 00:60:48:57:b1:41 mtu 1500 DHCP RARP
[2020-08-05 00:42:52.274776] IP-Config: eth0 hardware address 00:60:48:57:b1:40 mtu 1500 DHCP RARP
[2020-08-05 00:42:52.274776] IP-Config: no response after 2 secs - giving up
[2020-08-05 00:42:52.274776] IP-Config: eth1 hardware address 00:60:48:57:b1:41 mtu 1500 DHCP RARP
[2020-08-05 00:42:52.274776] IP-Config: eth0 hardware address 00:60:48:57:b1:40 mtu 1500 DHCP RARP
[2020-08-05 00:42:52.274776] IP-Config: eth1 complete (dhcp from 192.168.1.3):
[2020-08-05 00:42:52.274776]  address: 192.168.1.84     broadcast: 192.168.1.255    netmask: 255.255.255.0   
[2020-08-05 00:42:52.274776]  gateway: 192.168.1.1      dns0     : 0.0.0.0          dns1   : 0.0.0.0         
[2020-08-05 00:42:52.274776]  rootserver: 192.168.1.3 rootpath: 
[2020-08-05 00:42:52.274776]  filename  : pxelinux.0
[2020-08-05 00:42:52.274776] TFTP server is at 192.168.1.3

现场重现

1:reboot重启机器,我们的dhcp server端是个linux 系统,于是我们开启了tcpdump抓包,制定端口抓包数,过滤udp 67 68 dhcp client/server

sudo tcpdump -i eth0 -c 6555 -s 0 'udp and port 67 and port 68' -vvv

抓包结果如下:

在这里插入图片描述

问题分析

不了解dhcp可以科普文章: http://www.023wg.com/message/message/cd_feature_dhcp_message_format.html
这篇文章有个小问题,一会我们进行纠正。

从tcpdump 的信息看到尾数分别为40 , 41的两个网卡,41网卡dhcp成功,而40网卡没有,40发出了dhcpdiscover 然后dhcpserver发出了dhcpoffer报文,后面就没有了40网卡dhcp的进一步消息,这里就是启动时候那个timeout的原因。

我们带着这样的一位为什么dhcpoffer以后就没有消息呢?
我们有两种思路
1:猜测验证法,client没收到offer? client 没发出request?
2:发现异常对比法,对比dhcp log发现其中的异常点为出发点查看?

如果我们修改文件系统,让系统启动后可以手动调试,在client抓取对应网卡的报文,我们会发现对应网卡没有收到offer, 而另外一个网卡却收到了不属于他的offer,而且报文是单播的。我们根据一下内容知道dhcp回复的报文 client是可以选择单播还是广播的,由于之前一个网卡已经分配了ip地址,而且是同一个网段的,所以在网络内形成了相应的路由转发表,单播报文按照第一个网卡的路径进行转发了,导致第二个网卡再去申请ip的时候到达不了对应的网卡,这里明确一点,同一台机器上的网卡默认情况下是不通的,所以不会互相转发。你可以用ping -I 指定端口做测试。到这里,我们似乎知道了怎么修复问题,修改标志位,设置成广播。

flags 2字节
此字段在BOOTP中保留未用,在DHCP中表示标志字段。
只有标志字段的最高位才有意义,其余的位均被置为0。

最左边的字段被解释为广播响应标志位,内容如下所示:

0:客户端请求服务器以单播形式发送响应报文
1:客户端请求服务器以广播形式发送响应报文

bug修复

那为什么都是klibc 的ipconfig 会有这个问题呢,怎么修复呢?
我们下载klibc的代码,搜索对应log信息发现再ipconfig 目录下的main.c有timeout 的报错信息,沿着这条线,我们找到了dhcp_proto.c 文件

static int dhcp_send(struct netdev *dev, struct iovec *vec)
{
	struct bootp_hdr bootp;
	char dhcp_hostname[SYS_NMLN+2];
	int i = 4;

	memset(&bootp, 0, sizeof(struct bootp_hdr));

	bootp.op	= BOOTP_REQUEST;
	bootp.htype	= dev->hwtype;
	bootp.hlen	= dev->hwlen;
	bootp.xid	= dev->bootp.xid;
	bootp.ciaddr	= INADDR_ANY;
	#  源头在下面这行指定了具体地址,而且下面没有设置flag,默认单播
	bootp.yiaddr	= dev->ip_addr;  
	bootp.giaddr	= INADDR_ANY;
	bootp.secs	= htons(time(NULL) - dev->open_time);
	memcpy(bootp.chaddr, dev->hwaddr, 16);

修改方式

static int dhcp_send(struct netdev *dev, struct iovec *vec)
{
...
 - bootp.yiaddr = dev->ip_addr;
 + bootp.yiaddr = INADDR_ANY;
 + bootp.flags = htons(0x800);
...
}

修改目前自己的ip 地址应该是没确定的,让server改动广播方式发送。
重启编译klic,打包文件系统,启动系统,两个网卡都能分配到ip了。

通过这个我们熟悉了网络的debug过程和对协议的更深的理解。

举一反三:上面是客户端多网卡申请同一个网段的ip的问题,那dhcp server多网卡会不会有什么问题呢? 大家可以自己调试看看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值