IP层之分片包的整合处理---BUG修复

在之前章节中,笔者就IP层之分片包的整合处理进行了概念介绍,以及代码编写和仿真,在整体代码调试环节,笔者发现了一个问题,在本文中,笔者将就这个BUG进行说明,以及进行修复,讲解代码实现思路,验证代码逻辑正确性

注意看图片中的框选文字,这里说明,如何确定这是一个单帧包,这里的确定单帧包逻辑是不存在问题,但是直接将UDP报文输出是存在问题的,因为即使确定了当前输入进来的数据报文不是分片包,但该报文的的上一帧报文,可能是分片包,而由于分片包要进行巨型帧组合后输出,其报文长度可能为9000字节以上(假设),那么当前帧报文传输来时,巨型帧报文可能尚未传输完成,此时的输出数据总线是被巨型帧报文占用的。而根据输出赋值的优先级,会出现,巨型帧输出不完全,被新一帧数据报文顶替输出,以及当前报文优先级低,无法获得总线使用权,报文丢失,所谓的优先级,即是在一个时序控制逻辑内,else if的上下级,当两个else if语句满足时,总是先执行最上面的else if语句,单纯的文字解释这个问题,可能会给读者的理解造成混乱,笔者接下来就流程示意框图、代码仿真波形两方面展现这类情况,使得读者更加清晰的理解这些逻辑

上图所示,便是一种情况,在RAM中整合了三包分片数据包之后,进行数据帧输出,此时接连来了两包单包

此时,这两个单包按照之前的逻辑是会顶替当前包输出的,造成数据混乱,代码仿真如下图所示

图片一模拟了流程图中的情况,而图片二中则显示了这样的数据流动出现的问题,接下来将就这种现象进行解决方案的思考。

显然,为了避免这种情况,需要判断此时的数据输出总线是否被占用,如果数据输出总线被占用,则应该缓存本帧数据,待到数据输出总线空闲,再进行数据的读取,同时,若是数据到来时,数据输出总线是空闲的,则不需要缓存数据,直接进行输出,减少不必要的时间浪费。

那么还有一个问题,数据输出总线被占用期间,可能有多帧数据到来,都需要被缓存,那么数据长度同样应该被缓存,在本处理模块中不涉及数据类型,因为其下一级在本设计中一定属于UDP报文,所以不考虑数据类型的缓存,当涉及TCP/UDP两种报文时,会就IP_RX模块中的输出信号进行添加,这在之后讲解的TCP协议栈实现中,会进行具体介绍,大家可以点个关注,后续会有更多文章分享。

对于这些单帧数据包,使用FIFO进行数据缓存,使得逻辑处理简单,同时还需要注意一个问题,每次读取指定长度后,还需要暂缓下一帧数据的输出,避免背靠背传输,对数据总线处理的压力。

代码的主要难点是以下几方面

  1. 缓存分片数据包,并在缓存完成后进行输出
  2. 在分片数据包输出过程中,多个单包数据包到来,缓存至FIFO
  3. 在单包数据包输出过程中,再次到来单包数据包(因为分片包导致的数据堆积)缓存至FIFO
  4. 两个单包从FIFO中读出时,输出间隔问题,保证输出间隔大于10个周期,减轻后续处理压力,以及背靠背传输导致数据包输出长度计算错误问题
  5. 评定各种情况优先级,合理规划缓存以及读取
  6. 针对以上难点,应该多进行代码仿真,找出时序存在问题中,进行对应修改,多仿真是写出好代码的关键

整体仿真测试时序:

  1. 首先发送3472字节的巨型帧,分三次发送1480--1480--512
  2. 之后发送512字节单包,多次128字节单包--在巨型帧尚未缓存完毕以及巨型帧尚未输出完成
  3. 之后发送128字节单包--在输出总线输出单包数据时
  4. 最后发送128字节单包-在输出总线空闲时候
c 复制代码
initial begin
    #200
    /*ip frag*/
    @(posedge i_udp_clk)
    ip_frag_send(0,'d1480,1,0);
    #400
    @(posedge i_udp_clk)
    ip_frag_send('d0,'d1480,1,185);
    #400
    @(posedge i_udp_clk)
    ip_frag_send('d0,'d512,0,370);
    #400
    @(posedge i_udp_clk)
    ip_frag_send('d0,'d512,0,0);
    #400
    @(posedge i_udp_clk)
    ip_frag_send('d0,'d128,0,0);
    #400
    @(posedge i_udp_clk)
    ip_frag_send('d0,'d128,0,0);
    #400
    @(posedge i_udp_clk)
    ip_frag_send('d0,'d128,0,0);
    #400
    @(posedge i_udp_clk)
    ip_frag_send('d0,'d128,0,0);
    #20000
    @(posedge i_udp_clk)
    ip_frag_send('d0,'d128,0,0);
    #20000
    @(posedge i_udp_clk)
    ip_frag_send('d0,'d128,0,0);
end

情况一:对应仿真情况如下,可以看出分片包成功组合,数据长度3472字节,输出时序正确。

情况二:对应仿真情况如下,可以看出在巨型帧缓存输出完成后,被缓存的单帧数据包成功进行输出。

情况三:对应仿真情况如下,可以看出在输出单包数据完成后,在单包数据输出期间被缓存的单帧数据包成功进行输出。

情况四:对应仿真情况如下,可以看出在总线空闲期间到的数据包,被直接输出,不需经过缓存。

经过上述仿真模拟各种可能出现的情况,经验证后,输出时序正确,不会出现数据错误、覆盖、丢失等现象。

关于本次代码的实现、调试思路。大家有什么问题欢迎在评论区中进行讨论,有哪些考虑不到的地方,也请大家批评指正,可以关注下作者,后续会进行更多技术文章分享。

在下一章节中,笔者会将之前介绍的模块进行整合,组合成最终的UDP协议栈,当然,还不包括PHY层的处理,关于PHY层的处理,笔者也会在之后的章节进行介绍,以及UDP的上层及应用层协议,如IEEE1588,笔者也会进行介绍。

相关推荐
qq_397562313 小时前
51单片机的keil c51软件安装教程
单片机·嵌入式硬件·51单片机
xinxinhenmeihao3 小时前
python爬虫碰到IP被封的情况,如何解决?
爬虫·python·tcp/ip
坏柠4 小时前
STM32 HAL库实战:轻松实现串口通信驱动蓝牙模块与ESP8266开发
stm32·单片机·嵌入式硬件
FightingLod5 小时前
IIC通信协议详解与STM32实战指南
stm32·单片机·嵌入式硬件
苜柠6 小时前
网络通信(传输层协议:TCP/IP ,UDP):
网络协议·tcp/ip·udp
电子小子洋酱7 小时前
ESP32移植Openharmony外设篇(10)inmp441麦克风
单片机·物联网·华为·harmonyos·鸿蒙
智木芯语7 小时前
【21】单片机编程核心技巧:if语句逻辑与真假判断
单片机·嵌入式·#stm32·#stc8
honey ball10 小时前
时钟频率和GPIO的设定【DSP】
单片机·嵌入式硬件
c无序10 小时前
【Linux-传输层协议TCP】TCP协议段格式+确认应答+超时重传+连接管理机制(三次握手、四次挥手、理解TIME_WAIT + CLOSE_WAIT)
linux·网络·tcp/ip
爱学习的张哥10 小时前
ICMP、UDP以及IP、ARP报文包的仲裁处理
tcp/ip·fpga开发·udp