发明内容
本发明克服上述BCM1250的系统支撑的不足,提供一种针对包转发引擎的微内核,该微内核在满足功能开发的需求同时,可保持系统的简洁和高效。
本发明的技术内容:一种基于MIPS64的双CPU微内核,对BCM1250三种地址空间进行映射,对虚拟地址空间进行管理,支持1GB主存,内存管理针对包转发应用,将虚拟地址空间划分为代码段、数据段、栈空间、堆空间和包空间,并且在双CPU之间共享这些内存空间。
任务管理将两个CPU分别对应一个任务,每个任务包括多个线程。
堆空间包括K-heap和U-heap,两个CPU共享U-heap空间控制权,U-heap空间采用slab堆管理器和静态页表管理,CPU0独自拥有K-heap空间控制权,K-heap和U-heap支持cache-line大小对齐。
限制数据段不超过64KB。
定义全局数组和结构型全局变量时,必须在K-Heap空间中分配,其它全局变量存放在数据段空间中。
双CPU运行在各自的栈空间上,每一个任务的所有线程共用一个栈空间。
任务间通信机制包括共享内存和消息队列,任务间提供同步锁、互斥锁和读写锁。
线程间通信机制包括共享内存和消息队列,基于时间片线程调度实行主动退出和固定点切换。
对于定时发生的事件,提供一定时器,定时器的时间粒度为1ms。
本发明的技术效果:本发明微内核的系统最关键部件:内存管理和任务调度完全是为了满足包转发应用而设计,因此,系统简洁而高效。以简洁的体系结构,代码的完全可见性,使用户可以全面高效地分析系统的各个部件,从而提供了极高的可调谐性。在使用微内核进行转发功能的开发过程中,相对于OS,微内核体现了很大的优势。首先,开发周期短。由于微内核接口简单,任务调度简单,从而用户可以更快更好地应用微内核进行功能开发;其二,系统稳定性高。由于系统结构简单,使系统稳定性的获得更加容易;其三,在性能上,对于相同的转发功能,由于微内核更少的系统开销,所以获得了更高的转发性能。如下表所示,采用相同的转发代码,在不同的转发平台上的实际应用的测试结果:
支撑平台(双CPU) |
MPLS转发 |
IPv4转发 |
linux |
450Kpps |
350Kpps |
VxWorks |
700Kpps |
600Kpps |
微内核 |
1.2Mpps |
1Mpps |
(pps:packets per second(每秒处理包数))
具体实施方式
参考图3,微内核包括初试化、内存管理、中断管理、任务管理、设备管理、文件系统和调试模块。
微内核的初始化
包括:系统引导,内存初始化,双CPU初始化,中断初始化,设备管理初始化和任务初始化。
微内核的内存管理
BCM1250的CPU(SB1)是一个MIPS64的CPU,支持64位寻址。在BCM1250中需要对地址进行三级映射:虚拟地址空间->物理地址空间->主存地址空间。在系统中,支持1GB主存,微内核对BCM1250三种地址空间映射如下表所示:
虚拟地址空间 |
物理地址空间 |
主存地址空间 |
0x8000 0000~0x9000 0000 |
0x00 0000 0000~0x00 1000 0000 |
0x0000 0000~0x1000 0000 |
0xa800 0000 8000 0000~0xa800 0000 a000 0000 |
0x00 8000 0000~0x00 a000 0000 |
0x1000 0000~0x3000 0000 |
0xa800 0000 c000 0000~0xa800 0000 d000 0000 |
0x00 c000 0000~0x00 d000 0000 |
0x3000 0000~0x4000 0000 |
微内核的用户使用的地址空间是虚拟地址空间。如上表所示,映射方式的结果:虚拟地址空间并非连续的,但是,这种映射方式,避开了MIPS内存操作的TLB缺页中断处理,从而提高了系统的效率。这种不连续的虚拟地址空间也不会对虚拟地址空间进一步管理带来不便。
微内核对虚拟地址空间进行管理,虚拟地址空间划分为:代码段、数据段、栈空间、堆空间和包空间,并且在双CPU之间共享这些内存空间。如图4所示,代码段,数据段,K-heap堆空间和栈空间占256MB空间(地址范围:0x8000 0000~0x9000 0000);U-heap堆空间为512MB(地址范围:0xa800 0000 8000 0000~0xa800 0000 a000 0000);包空间为256MB(地址范围:0xa800 0000 c000 0000~0xa800 0000 d000 0000)。在分析MIPS64内存映射方式,应用的需求的基础上,设计了平面式内存管理。即,任何一个任务或线程对1GB的虚拟地址空间都是可见的,适合BCM1250硬件的SMP(对称多处理器系统)架构。
MIPS体系结构中,L2 cache对性能的影响非常大,在BCM1250中,当数据从内存中获得时,需要100个以上的CPU时钟周期的时延;当数据从L2cache中获得,只需20个CPU时钟周期的时延。因此,在整个系统设计中,特别是内存管理模块充分考虑高效利用L2 cache。利用MIPS体系中的pipeline,对关键数据通过预取指令放入L2 cache中,从而提高系统性能。在整个系统的数据结构设计上,以一个cache line的大小作为设计的基础,在一个cache line中存放更多有意义的数据。对于全局静态变量,将采用从堆空间中分配,可以更好地控制变量起始地址的字节对齐(一个cache line的大小)。
代码段
BCM1250软件所有的代码,包括微内核和转发模块的代码,都存放在代码段中。双CPU共享代码段空间。对于可能被多task调用的function应该是可再入的。对于可再入的function有两种实现方式:(1)利用who am I函数区分不同的CPU,不同的CPU使用不同的全局变量;(2)利用SPIN LOCK对全局变量加锁以实现互斥。
数据段
数据段存放系统的全局变量。微内核限制系统的数据段不能超过64KB。双CPU共享数据段空间。用户定义的全局变量若是被多个CPU访问,必须加以访问保护(互斥)。在系统中,为了限制系统的数据段不能超过64KB,微内核不允许用户定义全局数组和结构型全局变量。这样一来,微内核可以利用MIPS体系对不超过64KB的数据段提供更高效的寻址方式,从而获得更高的效率。同时,可以保证整个系统最终生成的可执行文件很小。当用户必须全局数组和结构型全局变量时,必须在K-Heap空间中分配。由于K-heap空间的分配对L2cache的敏感性,有助于提高系统的性能。
栈空间
系统中的局部变量和函数的参数都存放在栈中。双CPU运行在各自的栈空间上,因此每一个task拥有自己的栈空间。每一个task可以包括多个线程(thread)。一个task的所有thread共用一个栈空间,这样避免了因thread调度切换栈空间的开销。
堆空间
堆空间的管理是影响系统性能最重要的因素。堆空间包括K-heap和U-heap。K-heap空间是为了转发模块定义大块的静态数据而设计的。U-heap空间是为了转发模块在运行时动态申请和释放的空间。微内核分别采用两种堆管理器:简单堆管理器管理K-heap空间和SLAB堆管理器管理U-heap空间。
简单堆管理器是为系统提供静态数据空间而设计的。简单堆管理器提供字节对齐功能,从而使在设计转发模块时,用户可以更好设计数据结构,充分利用L2cache。同时,由于这部分空间是系统运行后分配的,从而保证了系统可执行文件足够的小。
SLAB堆管理器是为了系统动态申请和释放空间。通常SLAB堆管理器支持每次申请空间大小在32B~128KB范围内。在微内核系统中,提供了32字节到32M字节大小的空间分配。通常的SLAB堆管理器采用动态页表管理,动态页表管理的空间和时间开销都很大。在BCM1250系统中,由于包转发应用的特点,可预测出转发模块对U-heap空间的分配需求,因此可以采用静态页表管理,从而提高了空间分配和释放的效率。
对于双CPU,动态空间的控制(空间的申请和释放)可以有两种方式:共享堆空间和私有堆空间。若采用共享堆空间,两个CPU都可以申请和释放这个堆空间。因此,堆管理器的代码必须是可再入的。若采用私有堆空间,则拥有这个堆空间的CPU才可以申请和释放空间,而另一个CPU不能申请和释放空间。因此,堆管理器的代码不必是可再入的。两个CPU共享U-heap空间,CPU0独自拥有K-heap空间。应当注意的是,无论是共享堆空间或私有堆空间,两个CPU都是可见的,即可以对分配的空间进行读写。共享和私有是针对堆空间的分配和释放的权限。
K-heap和U-heap都支持一个缓存行(cache line)大小的字节对齐。从而充分利用L2 cache。
包空间
除了这四个空间以外,微内核还单独地划分出一块空间:包空间。包空间是为BCM1250处理的包而分配的空间。当系统收到一个包时,必须为这个包分配存储空间;当包发送后,这个包空间需要释放。采用最高效的动态申请和释放空间的方法来管理这块空间。
包空间采用最简单的free-list来进行管理。所有的空间被连接成一个单链,链上的每一个节点存储一个包,在链头申请,在链尾释放。CPU0负责申请,CPU1负责释放。让链上的节点个数始终大于系统所可能容纳的最大包数,因此可以避免由于多CPU而造成的加锁的额外开销。同时充分利用MIPS系统的L2 cache的特点,将包头的一部分通过预取指令存放在L2 cache中。
微内核的中断管理
MIPS64规定在固定地址存放异常或中断向量,MIPS64所有的中断处理都是在这一个入口,实行中断分派。
对于双CPU,对异常和中断进行如下管理:异常(Exception):
TLB exception是每个CPU独立的,相互不会干扰。其它exception目前都会造成CPU reset。CPU0 reset将使NP reset;CPU1..N reset是否使NPreset,由dead CPU的个数决定。
中断(Interrupt):
BCM1250的每一个CPU都有自己的Interrupt Mapper。大多数中断源是将中断广播到每一个Interrupt Mapper。只有两种中断是单播到指定的CPU。这两种中断是来自HyperTransport的中断和per-CPU mailbox interrupt。
对于广播的中断,对于一些CPU可以屏蔽该中断。若不同的CPU都执行中断处理程序,则处理必须是可重入的。
外部时钟中断是微内核调度的基础。时钟中断的时间间隔是100微秒,在这个时间间隔中,系统可以处理大约200个包。
微内核的任务管理
如图5所示,将BCM1250的两个CPU对应两个任务(task)。每一个task又包括多个线程(thread)。因此本系统是一个双任务,多线程的系统。包转发应用的特点是系统的任务数固定,并且任务间关系并不复杂,系统带宽比实时响应更加重要。因此,尽量减少调度带来的时间开销。
双任务
微内核支持基于双CPU的双任务。CPU0对应Task0,CPU1对应Task1。任务间共享:代码段空间,数据段空间,堆空间和包空间。每个任务独占自己的栈空间。对于K-heap空间,task0可以申请和释放,读和写;task1只能读和写。对于U-heap空间,task0、task1均可以申请和释放,读和写。任务间通信可以通过:共享内存和消息队列实现。
为实现任务间同步与互斥,提供了同步锁,互斥锁和读写锁。这些锁都是SPIN LOCK(自旋锁)。SPIN LOCK的实现是建立在MIPS64的LLD-SCD指令对的基础上。任务间的同步可以通过同步锁实现。任务间的互斥可以通过互斥锁或读写锁实现。当多个任务间对临界区都会有写操作时,使用互斥锁。当对临界区,一个task读,另一个task写时,可以使用读写锁。比如:在对路由表的管理时,转发流程模块对路由表只是读操作,由CPU1完成;转发控制模块对路由表是读/写操作,由CPU0完成。此时,可以使用读写锁实现这样互斥:CPU0读和CPU1读不冲突,CPU0写和CPU1读互斥。
包转发功能分布在不同的CPU上。ACL、接口管理在CPU0上实现,Ipv4转发、MPLS转发、L2VPN、L3VPN、组播、接入控制由CPU1完成,NAT和QOS由两个CPU各完成一部分。转发控制模块由CPU0来完成。微内核的各个模块也分布在不同的CPU上。
微内核为系统提供消息队列。在CPU0和CPU1之间,系统建立了消息队列(MQ)。转发模块可以使用消息队列将包从CPU0传送给CPU1。消息队列中实际上传送的是包的标识,从而实现了CPU之间包传送的零拷贝。一个典型的应用是:CPU0从外部接口接收到一个包(包的空间由CPU0分配),CPU0对包进行ACL处理,CPU0通过消息队列将包传送给CPU1,CPU1进行IPv4路由,CPU1将包从相应的接口发送出去,CPU1将包所占用的空间回收。
多线程
在微内核中,每一个任务可以包括多个线程。一个任务的所有线程可以共享该任务的所有空间,包括:代码段空间,数据段空间,堆空间,栈空间和包空间。线程间通信方式:共享内存和消息队列。
微内核的线程调度如图6所示,每一个线程可以有三种状态:pending、ready、running。在任何时刻,线程只能处于一种状态。Running状态表示线程占有CPU,正在运行。ready状态表示线程没有占有CPU,但有任务需要完成,准备就绪。pengding状态表示线程没有占有CPU,也没有任务准备运行。多线程的调度基于时间片,当一个running线程时间片用完时,就切换到pending状态。为了避免同一任务内的多线程间切换的系统开销,微内核的线程调度设计了主动退出和固定点切换。即,当一个running线程时间片用完时,必须将正在做的工作完成,即到达一个固定点时,才能切换到pending状态。或者,即使当前处于running线程的时间片未用完,线程也可以根据自己的情况选择退出,进入pending状态。
由于微内核的线程调度具有主动退出和固定点切换的特点。因此,线程间的切换不需要保存现场,也避免了线程间同步与互斥。从而,极大地提高了系统的性能。
对于定时发生的事件,微内核提供定时器(timer)。比如:当用户需要每1ms遍历某一链表,需要在timer中注册遍历某一链表的function,系统每隔1ms调用一次该function。Timer是一个特殊的线程。
微内核设备管理
为了提高效率,微内核实现简单的设备管理。为了简化系统的管理,减小系统开销,设备管理将完全由CPU0负责。CPU1在运行时,可能会使用如下设备。
CPU1会使用DMA的channel进行收发包。目前的实现是CPU0和CPU1使用不同的channel。随着系统的结构变化或需求变化,channel与CPU的对应关系会发生变化。
CPU1会使用串口输出。这时,CPU0与CPU1出现资源竞争,可通过互斥锁解决。
微内核文件系统
微内核实现基于CF卡的文件系统。CPU0负责文件系统的管理。文件系统中可以存放系统的异常信息或日志信息。
微内核调试模块
支持以下调试手段:串口输出,异常打印信息,Syslog和JTAG调试。从而为系统的软件的高效开发提供了可能。