近期的工作中,有一个对网络数据包进行处理的需求。根据系统功能,输入的大量数据包中,根据roce opcode的不同,有的数据包例如send请求等,需要直接上送给软件,让软件去决定处理;有的数据包例如write请求和read response等,需要查本地的queue状态表、memory protection表等,查表结果正常再直接写host内存并上送软件,如果异常则将异常信息上送软件;有的数据包例如中断数据包,需要直接写host内存。所有的数据包需要满足保序要求,后一个数据包不能越过前一个数据包去上送软件或者写内存。
根据该需求,不同数据包的处理方式不同,而且处理时间也有很大差别,因此有必要采用多条通道,分别实现不同的功能。通道1专门处理直接上送软件的报文,因为不需要修改报文内容,直接采用一个FIFO缓存之后输出即可。通道2专门处理需要查各种表的报文,得到所有查表结果之后在处理该报文。通道3专门处理直接写host内存的报文,也是不经处理直接缓存后送出。在三条通道前面设置分流器,根据输入报文的opcode不同发往不同的通道。三条通道后面设置mux模块,将结果汇聚到最终输出接口。
按照多条通道的架构,直接上送和写入的通道必然处理速度快,查表修改的通道处理速度慢,如果不特殊处理,则可能出现后输入的直接上送报文走通道1,比先输入的需要查表报文更快到达输入口,从而引起顺序错乱。如果要求一个报文处理完成再处理下一个报文,则严重损害性能,并造成报文积压。因此,本文采用增加seq num和eseq num的方式,进行保序的操作。新增16比特的域段seq num,具体修改方式如下图所示。

1.输入模块在将每一个报文转发到对应通道的同时,将seq num也在边带中发出。seq num初始为0,每次发出一个报文,seq num自增1。
2.每个通道在报文输出口,增加一个FIFO进行缓存。FIFO中除了报文之外,边带也包括该报文所带的seq num。通道要输出的报文需要比对自己的seq num和eseq num,如果对比不相同,需要留在FIFO中等待。只有比对相同的时候,才能发出,且发出时向eseq模块发出一个单周期脉冲信号update,让eseq模块更新eseq。
3.eseq模块负责管理和更新eseq num。初始eseq num=0,当任意一个通道发来update信号,则eseq num自增1。
4.进一步扩展,可在每个通道增加seq比对和超时逻辑,如果每个通道都和eseq无法对应,并且时间超过最大值,则将该通道当前报文丢弃,并上报异常。增加整体系统的健壮性。
通过这样修改,前一个慢速处理的报文先进入通道,防止堵塞后续快速处理的报文。直接上送和写入的报文直接送入自身通道,不堵塞后面需要查表的报文,可以实现查表报文的通道采用流水线架构保证性能。同时该结构也保证所有报文按顺序输出。