关于缓存与丢包,如何控制

控制/MCU

1883人已加入

描述

但凡牵涉到SmartNIC,都免不了牵涉到MAC IP。在网络设计里,MAC IP Rx端一般都是不接受反压的,随着报文类型对应的处理能力的不一样,在MAC收包处不可避免的存在报文缓存和丢包。

》关于缓存与丢包,如何控制    

先来谈谈一般像100G Mac 这种类似的IP的Rx的特点:

rx接口均为Flow类型(即只有valid而没有ready)

一般带有sop、eop

在eop处会指定报文是否有错误

    既然不接受反压(没有ready),那势必需要在流量入口处设置缓存,并当缓存满时允许丢包。    

 由于在报文eop处可能存在错误,对于错误的报文,往往不会发往数据链路的下游,同时有时候下游会要求报文中间不能存在空拍(即要求整拍输出)。而一提到报文缓存,大多数人想到的就是FIFO,故在很多开源设计里,往往都用FIFO的形式来进行搭建:

FIFO存储

    一般会设计两路FIFO,一路用来存放数据,另一路用来存放报文的信息。对于两路FIFO的输入侧,一般大多数的设计思路是:

在报文SOP首拍时判断Data Fifo是否afull拉起(Msg FIFO一般设计的容量足够满足不会afull先于Data FIFO拉起),若拉起,则这一帧报文认为无法进行缓存,需丢弃,否则则这一拍报文在处理时,可以直接写入Data FIFO,无需再考虑afull信号。

在报文eop尾拍时,若该数据报文能压入Data FIFO,将报文是否有错误及一些其他信息压入Msg FIFO。

    在两路FIFO的输出侧,一般的设计流程是: 等待两路FIFO均不会空 从Msg FIFO中判定要处理的报文是否存在Error,若存在Error,将报文从Data FIFO中取出直接丢掉,否则送往下游。在报文EOP时,从Msg FIFO中读取出该报文。

    流程没问题,用起来也没问题。那么接下来我们来分析下这里的设计是否能优化下。     

对于进入的网络报文,Data FIFO从功能上来讲是一个严格的Package FIFO,一帧报文在sop时能缓存那么就意味着这一帧报文就一定能缓存,所以在设计afull时就需要考虑最大报文长度。以9600Byte为最大报文长度而言,当总线位宽是512 bits时,其缓存需要150个entry。那么在设计Data FIFO时其至少要在还剩下150个Entry没有使用时就拉高afull。

FIFO本身的作用是吸收瞬时流量,设置如此大的afull阈值是否也就意味着极大的空间浪费?明显afull拉高时我们甚至有可能还能多缓存150个数据报文(如果这段时间恰好下游处理能力不足),而这些报文就这么丢弃掉了(当然你可以说我增大FIFO的深度不就完事儿了么,也没毛病,但空间浪费的情况始终存在)。     

其次,为了避免向下游发送错误的报文,我们还需要专门维护一个Msg FIFO(当然也可能存储一些报文长度等类型报文,这里仅考虑存储是否报存在报文错误)。     

如果从设计“精益求精”的角度,这里的设计能否“优化下呢?”

》异形FIFO

    回到上面的问题,之所以设置afull也好还是专门设置一个MsgFifo也好其都是因为写入FIFO的数据不能回退所导致的。当一帧报文在写入过程中写到一半发现FIFO满了这时候会导致有半包数据。当写到最后一拍数据发现有error标志又无法把这一帧报文给回退掉,故而采取上面的那种设计。

    那么,如果FIFO能回退是否就解决了这个问题?

    关于FIFO的原理,估计大多数面试官都可能会问到过,FIFO状态的维护说白了就是一个读指针(read_ptr)和一个写指针(write_ptr)。之所以不能数据回退,其原因在于没有维护之前状态的写指针所导致。

    那么这里我们不妨维护一个能回退状态的指针即可:

FIFO存储

    这里我们用write_ptr来维护数一帧数据报文成功写入后的指针,write_ptr_tmp,read_ptr则用于表示正常FIFO的读写指针。只不过write_ptr_tmp相较于普通的FIFO有回退的功能。

    对于写操作,为避免一帧数据报文在写操作过程中出现中间有一拍出现full而后消失,我们则需要维护一个wen_flag标志寄存器:

FIFO存储

    那么对于数据写使能的处理则可以表示为:

FIFO存储

    即当遇到full或者pkg_wen_flag为0或者error时wen均不使能,数据不不再写入RAM。    

    那么对于write_ptr_tmp,其处理逻辑为:

FIFO存储

    在一帧报文进入时,每成功写入一拍数据,则write_ptr_tmp就会加1,一旦出现数据无法成功写入,则其立即回退到write_ptr保存值(此时继以后的报文wen均会拉低),实现回退功能。

    而对于write_ptr则更为简单了:

FIFO存储

    仅需要在报文的最后一拍判断是否写成功,如果写成功,那么则可以更新write_ptr。

    至于读侧,则可以正常根据read_ptr,write_ptr来进行处理,天然的实现了整包输出的特性。

    而为方便给用户提示报文是否写入成功,我们可以定义如下:

FIFO存储

    即判断最后一拍数据报文能否正常的写入即可。

    如此,对于FIFO简单的一点改动,可以使我们充分压榨RAM的资源,避免因为设计而导致的本不必丢失的报文丢失,何乐而不为呢~

》代码附录     

最后,贴上完整的代码:

FIFO存储







审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分