RT-Thread-packages / wiznet

WIZnet TCP/IP chips (such as W5500/W5100..) SAL framework implement.
Apache License 2.0
49 stars 35 forks source link

修复DHCP IP续租过程会重新DHCP的问题 #68

Closed AingSu closed 2 years ago

AingSu commented 2 years ago

详情见:bug:w5500 DHCP续租逻辑问题

mysterywolf commented 2 years ago

https://github.com/mysterywolf/formatting 用这个扫一下你提交的代码

xiangxistu commented 2 years ago

这里面可能有以下几个问题:

  1. ioLibrary 的部分是 wiznet 库中的,这部分的改动看到你这边是加了一个 dhcp_tick_1s 函数,该函数的目的是获取 DHCP client 解析出的续约时间是吗?

  2. 看了你的文章,你是对 DHCP_run 这个线程进行了修改,修改了函数的返回值。这个部分是做什么考虑呢?


对于 DHCP 服务器的续约问题,最常见的问题是超期续约,一般设定时间为续约时间的一半,且续约后的 IP 地址是继承之前的 IP 地址,不会做更改。你现在修改后的方案,看起来是租期到达后续约,貌似不太符合标准。


你所提供的重复续约问题,是插拔网线的场景下的描述,应只改动这个逻辑,续约时间的修改,看起来不太符合规范。

xiangxistu commented 2 years ago

又看了你的另一个帖子,租期续约应当走DHCP Request,应该去掉调用正常获取 IP 后调用 DHCP stop 的逻辑,这样做即可打到目的。

AingSu commented 2 years ago
  1. “dhcp_lease_time” 这个才是从路由器上获取的租约时间,“dhcp_tick_1s” 这个是本机计时的时间 dhcp_work_times = (getDHCPTick1s() > getDHCPLeasetime() / 2) ? 0 : getDHCPLeasetime() / 2 - getDHCPTick1s(); rt_work_submit(dhcp_work, (dhcp_work_times+1) * RT_TICK_PER_SECOND); 如上,只是为了计算工作队列时间,和DHCP_run()联动 ,保证工作队列每次进来时,dhcp_tick_1s 都能略大于租期一半的时间,所以传入工作队列时 dhcp_work_times 还需+1 (否则 DHCP_run() 775行 可能判断不过)

  2. 修改了DHCP_run()中 “STATE_DHCP_LEASED” 和 “STATE_DHCP_REREQUEST” 分支的返回值。 如果处于续约的过程,返回值为默认的 “DHCP_RUNNING” 这样可以避免,打断DHCP_run的续约过程 且续约完成后会自动进入到 “STATE_DHCP_LEASED” 分支,这时 dhcp_tick_1s因为被重置,返回值才为 “DHCP_IP_LEASED” 这时候才会进入到提交工作的环节中。这样逻辑才是对的。

  3. 我这样做就是为了保证每次都能 1/2 时间 时能正常续约。

  4. 重复续约不是我插拔网线的场景,是每次超时就会这样,如果可以的话你可以测试一下(路由器 租期设置最短,wireshark抓一下DHCP 你就会发现它每次都在重新DHCP) PS: gif图的演示让你会错意了,因为我第一次修改插拔后不能DHCP了。

AingSu commented 2 years ago

又看了你的另一个帖子,租期续约应当走DHCP Request,应该去掉调用正常获取 IP 后调用 DHCP stop 的逻辑,这样做即可打到目的。

没看懂这句话的意思,但是如果获取到了ip后, 调用DHCP stop不就会重新DHCP吗?

xiangxistu commented 2 years ago

又看了你的另一个帖子,租期续约应当走DHCP Request,应该去掉调用正常获取 IP 后调用 DHCP stop 的逻辑,这样做即可打到目的。

没看懂这句话的意思,但是如果获取到了ip后, 调用DHCP stop不就会重新DHCP吗?

之前是完成后调用 DHCP stop,这样会清除 DHCP 的状态,这个应该是续约时会重新走一遍 DHCP 流程的原因。 代码中去掉获得 IP 后调用 dhcp_stop 的逻辑,应该就不会走一遍 DHCP 流程了。


很抱歉,我现在手里没有 wiznet 的硬件,没有办法和你一起验证。

AingSu commented 2 years ago

又看了你的另一个帖子,租期续约应当走DHCP Request,应该去掉调用正常获取 IP 后调用 DHCP stop 的逻辑,这样做即可打到目的。

没看懂这句话的意思,但是如果获取到了ip后, 调用DHCP stop不就会重新DHCP吗?

之前是完成后调用,DHCP stop,这样会清除 DHCP 的状态,这个应该是续约时会重新走一遍 DHCP 流程的原因。

对,没错,但是如果只是单纯把这里删除是不行的

  1. W5500还没收到 ack 就被退出了,如果有IP冲突,没法继续往下了。
  2. dhcp stop只是一部分的原因,还有前面的dhcp_init。工作响应后会重走这个地方,所以还需加限制
  3. DHCP_IP_LEASED 分支这里 wiz_dhcp_retry_times = dhcp_times; 不能相等,否则还是会重新DHCP
  4. wiz_link_status_thread_entry()中检测到网线插上还需重置一下状态,否则插拔后,无法及时DHCP (因为2. 的原因 static uint32_t dhcp_status)
  5. 增加的 dhcp_work_times 只是为了和 DHCP_run中的 “STATE_DHCP_LEASED”分支时间对齐,避免各走各的。
xiangxistu commented 2 years ago

开启 _DHCP_DEBUG_ 也可以达到短时间内多次 DHCP 续约的目的,与设置路由器的续约时间是一致的。

xiangxistu commented 2 years ago

OK,这样来说,两种方法都能实现续约目的;既然大佬这边已经实现了,那就合并这个了吧。(^o^)/

AingSu commented 2 years ago

感谢,我不是大佬,使用过程中发现丢帧了,才解决了这个问题,顺便分享给大家。(^o^)/

xiangxistu commented 2 years ago

感谢,我不是大佬,使用过程中发现丢帧了,才解决了这个问题,顺便分享给大家。(^o^)/

o͡͡͡╮░ O ◡ O ░╭o͡͡͡

解决了问题就是大佬,哈哈!😁