背景技术
随着网络技术的高速发展,一方面对交换机、防火墙等网络设备的处理性能要求越来越高,另一方面音频/视频、P2P、云计算等各种新应用、新业务层出不穷,迫使网络设备集成的安全防护业务越来越复杂,造成整机的处理性能急剧下降。经过大量的实际测试,申请人发现目前硬件的处理能力、驱动底层的收发效率都是有保证的,网络设备转发性能的瓶颈主要在协议栈上层处理。上层处理对业务本身关注较多,导致处理效率低下,整机的转发性能无法得到有效的提升。当前的网络设备基本都是驱动收到报文后直接上送操作系统(如Linux)协议栈做业务和转发处理。协议栈在报文转发过程中会查二层转发表、路由表、ARP表等一系列表项,如果报文还需做其他业务(如报文审计、NAT转发、IPsec等),则还需要查找对应的各种表项,做相应的业务处理。
网络设备在转发过程的各个阶段,不但要查询各种转发表项,为了满足业务需要,往往又会嵌入很多业务处理流程,业务处理也需要查询一系列表项,而且几乎所有的表项都是相互独立的。过多的表项查询次数和业务处理,不但提高了代码复杂度,更重要的是大大的降低了对报文的转发性能。
请参考图1,目前可以使用快速转发技术(简称快转)来解决转发性能低下的问题。快转的目的是简化和优化报文的处理流程,将设备的主要流量在驱动层面使用快转模块进行转发,少数快转模块无法处理的报文经过传统流程上送协议栈处理。快转原理利用同一个会话的报文转发策略相同来实现的。会话的定义标准有很多,其中最流行的是采用五元组的方式来定义,所谓五元组通常包括源IP地址、目的IP地址、源端口号、目的端口号以及协议类型。快转技术整体设计思路是:当一个会话的首报文到达设备时,正常上送协议栈做转发及业务处理,同时将相关处理结果信息收集好下刷到驱动的快转表项中,后续当同一五元组的后续报文再次到达设备时,只需在驱动进行一次快转表查找操作即可完成对报文的处理和转发。
快速转发技术大大提高了设备整体的转发效率。然而快速转发技术也有其缺陷。快转模块通常包括有转发表。转发表的表项内容由协议栈收集好下刷给驱动,表项大小根据内存定制,原则是在不影响其它流程的基础上,建立尽可能多的转发表,让大部分报文都能走快转。但这样一来转发表可能会很大,如果使用数组存储,在查找的时候就需要遍历整个数组,效率太差。
发明内容
有鉴于此,本发明提供一种快速转发装置,应用于网络设备上,用于基于会话对报文进行转发;该装置包括:快转执行模块以及表项处理模块,其中:
快转执行模块,用于根据报文的会话特征计算Hash值,根据该Hash值确定索引表中对应的Hash桶;其中所述索引表包括N个Hash桶,N为大于等于2的自然数,每个Hash桶包括M个索引表项,M为大于等于2的自然数;其中每个索引表项保存有指向转发表中一条转发表项的转发指针;所述快转执行模块进一步用于遍历该Hash桶中的M个索引表项,并且在遍历过程中查找到与会话特征对应的转发表项时根据转发表项保存的处理结果信息执行报文转发,而在遍历过程未查找到对应转发表项时提交上层转发模块处理;
表项处理模块,用于将上层转发模块对报文的处理结果信息保存在转发表项中,并根据会话特征计算出Hash值,根据Hash值确定对应的Hash桶,将指向该转发表项的转发指针保存在Hash桶中未被占用的索引表项中。
本发明还提供一种快速转发方法,应用于网络设备上,用于基于会话对报文进行转发;该方法包括以下步骤:
步骤A、根据报文的会话特征计算Hash值,根据该Hash值确定索引表中对应的Hash桶;其中所述索引表包括N个Hash桶,N为大于等于2的自然数,每个Hash桶包括M个索引表项,M为大于等于2的自然数;其中每个索引表项保存有指向转发表中一条转发表项的转发指针;
步骤B、遍历该Hash桶中的M个索引表项,并且在遍历过程中查找到与会话特征对应的转发表项时根据转发表项保存的处理结果信息执行报文转发,而在遍历过程未查找到对应转发表项时提交上层转发模块处理;
步骤C、将上层转发模块对报文的处理结果信息保存在转发表项中,并根据会话特征计算出Hash值,根据Hash值确定对应的Hash桶,将指向该转发表项的转发指针保存在Hash桶中未被占用的索引表项中。
本发明采用新的表项结构和查询设计方式,可以从容应对Hash冲突的问题,并且提供扩展机制应对严重Hash冲突的能力。
具体实施方式
本发明将表项设计为哈希(Hash)结构,对于Hash结构来说一个重要问题就是解决Hash冲突。然而考虑到转发表项本身比较大,直接使用转发表项处理冲突,内存开销太大,因此本发明还引入一个索引表。转发表中表项数目个数为N时,索引表设计成N*M,其中N为索引表中Hash桶数量,M为桶深,即一个Hash桶中索引表项数量。索引表项包括两个字段:key和转发指针,共X个字节。以下介绍本发明一个较佳实施方式的实现过程。本发明一种实施方式中提供一种快速转发装置,该装置包括快转执行模块、表项处理模块以及临界处理模块。
首先介绍表项的添加过程,表项处理模块在初始化时申请好两段连续的内存空间用来分别存放转发表以及索引表。由于表项使用连续内存使得缓存预取时可以将多个表项一次取出,提高缓存命中可以大大提高缓存命中,缩小内存存取速度与CPU指令处理速度的不匹配,充分利用CPU使用率;而且内存一次申请出来,快转模块自己负责内存管理,避免频繁的向内核申请释放内存,提高了内存管理效率。在优选的实施方式中,转发表使用两个链表:使用链表以及空闲链表。其中使用链表存储已经添加的正在使用的转发表项,空闲链表存储空闲的表项,初始化的时候表项处理模块将所有转发表项都串接在空闲链表上。所谓空闲链表相当于内核中的空闲内存池,初始化时将所有转发表项串接在空闲链表是指将转发表项要占用的内存串接在空闲链表,此时转发表项的内容都是无效的。只有在添加转发表项后,才将转发表项从空闲链表删除并串接到使用链表,此时转发表项才是有效的。此处相当于维护一套内存管理机制,空闲链表相当于内核中没有使用的内存,使用链表相当于正在使用的内存。
对于会话的首个报文来说,由于查不到对应转发表项会被快转执行模块上送上层转发模块处理(通常也称为协议栈处理),协议栈做完业务处理收集好处理结果信息后,将处理结果信息交给表项处理模块。表项处理模块首先根据报文五元组计算Hash值(Hash算法通常是预定的),根据Hash值选定对应Hash桶,在Hash桶内找到可用的索引表项,然后再从空闲链表头部获取一个转发表项,将该转发表项串接到使用链表的尾指针上并更新使用链表的尾指针,最后把收集好的处理结果信息下刷至转发表项中,并设置索引表项中的转发指针指向该转发表项。
一旦某个会话对应的转发表项以及索引表项建立之后,快转执行模块就可以利用索引表以及转发表项来对该会话的后续报文执行快转了。快转执行模块首先根据会话标识(比如五元组)计算出Hash值,在索引表找到对应的Hash桶,如果所述宏定义为M,那只需要遍历当前Hash桶就可以了。由于Hash桶深为M,那么快转执行模块最多可能需要执行M次查找,快转执行模块查表包括以下步骤:
步骤10,确定是否已经完成Hash桶中的索引表项遍历,如果是转步骤11,否则转步骤12;
步骤11,将报文上送协议栈进行处理;
步骤12,在Hash桶中选定下一个表项(初始为零),根据该表项内存放的指针找到对应的转发表项;
步骤13,比较该转发表项保存的五元组是否与报文的五元组匹配,如果是转步骤14,否则返回步骤10;
步骤14,提取转发表项中的处理结果信息执行快转。
在优选的实施方式中,假设索引表的Hash桶深M为6,当某个特定Hash桶内的6个表项都被占用时,表项处理模块将往相邻的下一个Hash桶中存储数据。此时表项处理模块需要做特别处理,在实现上需要在添加与查找表项时遍历两个Hash桶,也就是Hash值对应的Hash桶以及下一个相邻的Hash桶,也就是要遍历12个表项。请参考表1的示例,在正常情况下,每个Hash桶内的Hash值都是相同的,假设一个报文的五元组Hash值=HV1。HV1所在Hash桶X内6个表项都已经被占用,此时HV1+1所在下一个Hash桶Y的第一个表项也被占用,此时HV1被写入Hash桶Y的第二个表项或者其他空闲的表项中。
表1
上述处理可以极大提高Hash冲突的处理能力,在不占用额外占用内存的前提下仅仅牺牲少量的查找(最坏的情况下多扫描6个表项)时间,就能将将Hash冲突处理能力由6放大到12。在代码实现上,可以将12这个值定义成宏,对于某些极端的冲突特别严重的业务环境,可以再放大这个宏的值,比如放大到18。而放大的过程仅仅是修改定义,在代码修改上极为方便。如果所述宏定义为2M,那么步骤10则在两个Hash桶中进行遍历,相当于要额外遍历下一个Hash桶,同样的道理如果宏定义为3M,那么则需要额外便利下两个Hash桶。
当会话老化,比如定时器超时仍然没有新的报文到达时,表项处理模块可以预删除该转发表项,将对应索引表项与转发表项的标志位更新为无效,标识该表项已经无效,保证后续该五元组的报文不能命中表项即可。在优选的实施方式中,考虑到转发表的使用链表与空闲链表都是全局的,若系统采用多核体系,则该转发表会被所有CPU共享。此时在多核体系结构下对全局变量访问可以使用自旋锁等并发保护机制,然而并发保护必然导致其它CPU必须等待,效率低下。为了避免这一点,本发明中引入一个共享处理模块,用来执行表项真正删除,表项删除模块有一个单独CPU内核线程来实现,该线程可以集成向协议栈上报驱动快转的流量统计等任务,在遍历使用链表上报流量的同时查询表项的标志位,如果该表项已经被置为无效,这时才将该表项真正删除掉。
进一步来说,在多核体系下需要考虑临界状况。假设CPU1命中了一个转发表项,正根据该表项内容做快转处理时,CPU2刚好在删除这个表项。如前所述,如果该转发表项被删除就会挂接到空闲链表的尾部,如果此时空闲链表就剩最后一个(即刚删除的转发表项),则下一次添加表项时必然就会使用刚刚挂接到空闲链表尾巴上的这个刚删除的表项上,这时新添加的表项就会将之前的信息覆盖,而此时CPU1还在根据这个表项的信息做业务处理,因此会导致业务处理出错。为了避免这种情况发生,现有技术中一般处理方法是使用定时器延迟删除,而定时器是通过软中断实现,中断就需要打断CPU对程序的执行,影响效率。
为了避免这种情况发生,一般处理方法是使用定时器延迟删除,而定时器是通过软中断实现,中断就需要打断CPU执行,影响效率。本发明采用的方法是为CPU多申请若干预留表项,在一种优选的方式中,本发明为网络设备的每个CPU预留至少一个表项。所谓预留表项是指始终保持有一定数量的表项不被占用,比如说预留32个表项,那么当系统仅仅剩下32个表项时,不可添加新的转发表项。相应地,表项处理模块需要根据预设的预留表项数量执行处理信息保存到转发表项的操作(也就是添加表项操作),当剩余空闲表项数量等于预留表项数量时,停止当前转发表项的保存操作。这里所说停止可以是暂缓也可以是放弃,比如说等到新的表项被添加到空闲链表的尾部时再执行当前转发表项的保存操作。这样的处理可以以确保预留表项数量始终不变。
请参考图3,当CPU1已经查询到表项A并正在根据表项A执行转发时,CPU2将表项A删除,此时由于还有32个表项预留,所以其它CPU需要添加表项时,会先用到表项1到表项32。表项A虽然被删除了(可能仅仅被标记为无效,但表项中的信息仍然在),但是由于预留表项的存在新添加的表项短时间内不会使用表项A。此时在表项A之前还有32个预留表项,而CPU1正在根据表项A转发,所以CPU1不可能去添加表项,也就是说即便其它31个CPU同时都在添加新的转发表项,也不会占用到表项A。所以在一个CPU完成表项添加的时间内,表项A中的转发信息不会被覆盖。简单来说,由于预留表项的存在,表项A被预留表项保护起来了,因为被删除的表项A会添加到空闲链表的尾部。
CPU1根据表项A中的转发信息转发时,表项A仍然是删除之前正确的信息。如前所述转发表项添加需要上层转发模块进行一次完整的处理,获得处理结果信息才能完成新的转发表项的添加工作。而事实上快转的处理速度要远远快于上层转发模块处理报文和添加转发表项的速度。在一些典型的应用场景中,快转处理一个报文的时间是远小于正常转处理一个报文的时间的,在一些典型应用测试结果中,快转处理一个报文的时间是上层转发模块处理时间的1/15),因此牺牲非常少量的内存即可换取效率的提高。而且事实上,其他CPU同时在添加表项的情况非常之少。因此预留表项在某些程度上也可以小于等于CPU的个数。
本发明采用新的表项结构和查询设计方式,可以从容应对Hash冲突的问题,并且提供扩展机制应对严重Hash冲突的能力。而且本发明通过合理的预留表项机制,通过消耗极少量的内存资源避免了多核系统中采用延时删除而引发的CPU执行效率下降的问题。
以上所述仅为本发明的较佳实施例而已,并不用以限制本发明,凡在本发明的精神和原则之内,所做的任何修改、等同替换、改进等,均应包含在本发明保护的范围之内。