摘 要:在对网络通信可靠性要求高的系统中,需要对网卡进行双冗余备份。当正常通信的网卡或线路出现故障时能自动地切换到备份网卡。本文详述了实时操作系统VxWorks下一种双网卡冗余备份技术的实现。

关键词:实时操作系统VxWorks;网络控制器;双冗余备份

1引言

随着网络技术的成熟,以太网已成为各种控制系统接口互连的主要媒介。在某些特殊的应用场合,为了提高系统的可靠性和抗毁性,需采用双冗余网络技术。在双冗余网络中,每个节点都采用两块网卡(或单板双卡),中间用两个HUB或交换机互连。当某个节点一块网卡故障,或网线损坏,或其中一个HUB或交换机故障时,网络仍能正常运作。

双冗余网络虽有两块网卡,两条通道,但对于高层应用系统来说,仍呈现单网卡的特征。具体来讲,每个节点的两块网卡只能有一个物理地址,一个IP地址,否则网络就不能进行正常通信。

现在大多数操作系统(如Windows、Unix、Linux等)均支持多网卡,但均非冗余设计,每块网卡都有独立的物理地址和IP地址,以独立的形式让应用系统使用。根据目前海军对高性能实时系统的要求,我们对VxWorks环境下的双网卡的切换以及冗余备份的设计方法及要点进行介绍。

2VxWorks介绍

VxWorks操作系统是一种具有工业领导地位的高性能嵌入式实时操作系统,是嵌入式开发环境Tornado的关键组成部分,它为程序员提供了良好的可靠性和卓越的实时性,因此被广泛地应用在通信、军事、航空、航天等高精尖技术及实时性要求极高的领域中。

就广泛使用的Unix和Windows操作系统来说,它们都是很好的应用开发和交互式应用的操作系统平台,然而他们并不适合于实时应用。而从另一方面考虑,以前出现的实时操作系统都没有为应用开发和应用的非实时组件(譬如向GUI)提供很好的运行环境。而Wind River的哲学是利用两个相互协作的操作系统来互相补充对方的不足(譬如VxWorks和Windows),让他们各尽所长。VxWorks为应用提供实时性,而主机被用来进行应用开发和运行非实时的应用程序。

3冗余切换

在系统的运行中设备由于硬件或软件原因出现故障是时有发生的事。采用有效的防错容错机制对一个需要稳定运行的系统是必需的。冗余备份技术是对容易出错的硬件设备进行冗余备份。当其中一个设备由于某种原因不能正常工作时,另一个设备马上就可以代替这个设备完成相同的功能。本文只是针对网络因素导致系统故障的情况分析对网络适配器的一种可行的错误保护机制。

通常如果在某一系统中安装两块网卡,它们分别有不同的物理和IP地址。当其中一块网卡出现故障时,另一块网卡不能实时地代替它继续工作,这是因为它们的物理地址不同,所以它不能接受到发向前一块网卡的数据。但在对网络通信可靠性要求高的系统中,需要对网卡进行双冗余备份,一块网卡在正常工作时使用,另一块网卡作为备份。备份用的网卡不发送或接收数据,但已经处于激活状态。在正常通信的网卡出现故障时,备份用的网卡能实时地、自动地切换过来继续工作。显然,这就要求两块网卡只能使用同一个物理地址和同一个IP地址。从应用程序的角度看,只会看见一块网卡在工作。应用程序不关心是哪块网卡在工作,也不关心网卡之间是如何切换的。

在VxWorks系统中,相同类型的网卡使用同一个驱动程序,网卡之间由NDIS提供的句柄来区别。NDIS调用NIC驱动程序的接口函数时,都会把网卡的句柄传入函数中。这就为在驱动程序中实现冗余备份提供了基础。双网卡驱动程序实现后与高层协议驱动程序绑定在一起,对应用程序完全透明。因此要实现网卡的双冗余备份,最理想的办法是在NIC驱动程序中实现。但是如果采取这样的方式我们必须要有VxWorks下的所用网卡的驱动程序,而对于一般的用户而言,开发这样一个驱动程序的难度是很大的。目前也有一些研究单位完成了这些工作,但是它们要求的价格过高,软硬件共需要15000元左右,这对于一般小型用户是比较高的。所以我们选择在基本不影响冗余备份效果的基础上,在高层的用户程序中实现这一目标。

在早期的VxWorks5.1.x中,系统是不支持多网卡的。通常,VxWorks在启动时仅仅对引导它启动的那块网卡进行初始化。如果需要在某一特定的目标机上从一块网卡换到另一块网卡(例如从ene型换到ENP型的网卡),我们可以通过系统提供的函数以及来实现网卡间的切换。我们所需要做的是连接所需要的网卡并删除前一个网卡的路由。我们可以调用特定网卡的连接函数:enpattach(),enettach()等等。例如enpattach()函数为网卡连接中断并建立enpsoftc,系统将为该网卡作相应的初始化。

    enpattach (0,0xffde0000,192,3);
    /* 参数依次为:网卡在系统中的单元号,enp's的共享内存地址,要连接的中断向量,中断级 */

需要说明的是,在VxWorks 5.1下虽然这些连接函数都有一个unitNum参数,似乎可以支持多个网卡。但其实并非这样,在后面的叙述中我们可以看到它没有IP MAX UNITS这个宏的定义,所以并不支持多网卡,unitNum的值一直是0,读者们可以在源代码中查看一下。

因为当VxWorks启动时它将一个缺省的网络接口加载到网络接口表中,所以在连接到需要的网卡后需要再调用ifRouteDelete()函数以删除连接到某一指定网卡上的路由。

ifRouteDelete("ln", 0); /* ln为需要关闭的网卡名 */

再利用ifMaskSet()来定义子网掩码

ifMaskSet("enp0", 0xFFFFFF00);

最后再用ifAddrSet()对指定的网卡分配一个IP地址

ifAddrSet("enp0", 147.11.1.230");

这样就完成了VxWorks5.1下多网卡之间的的切换。

就VxWorks 5.4来说,它本身是支持多网卡的。以下我们描述SBS PC104系统如何在VxWorks下支持多个网络适配器的软件冗余切换(以ne2000型为例)。

首先我们需要通过网卡配置程序对硬件环境中的所有网络适配器进行IO基址和IO中断的配置。本文假设系统中只有两个网络适配器,其IO基址和IO中断号如下所述。实际系统中可能会有多个网络适配器,其配置方法可依法类推,只要网卡的IO基址和IO中断不会和系统中的其他设备冲突即可。

修改 \Tornado\target\config\pc486目录中的config.h文件,

#define IO_ADRS_ENE 0x320 /*第一块网络适配器的IO基址*/
#define INT_LVL_ENE 0x05 /*第一块网络适配器的IO中断号*/
#define IO_ADRS_ENE1 0x300 /*第二块网络适配器的IO基址*/
#define INT_LVL_ENE1 0x09 /*第二块网络适配器的IO中断号*/

修改 \Tornado\target\config\pc486目录中的configNet.h文件,

在VxWorks的增强形网络设备的驱动参数表endDevTb1中添加对两个网络适配器的驱动项。

#ifdef INCLUDE_ENE_END
{0, END_ENE_LOAD_FUNC, ....., FALSE}, /* 0 表示加载第一块网卡 */
{1, END_ENE_LOAD_FUNC, ....., FALSE}, /* 1 表示加载第二块网卡 */
#endif

END_ENE_LOAD_FUNC为设备加载回调函数。由于系统中的两个网络适配器是同种类型的网络适配器,所以使用相同的加载回调函数。

修改\Tornado\target\config\pc486目录中的sysNe2000End.c:

SysNe2000End.c包含了网络适配器的实际加载代码,END_ENE_LOAD_FUNC定义的函数sysNe2000EndLoad(char*,void*)就在该文件中,需要修改sysNe2000EndLoad函数如下:

if(pParamStr[0] == '0')
sprintf(cp, ne2000ParamTemplate,
	IO_ADRS_ENE,
	......
	ENE_OFFSET);
else if(pParamStr[0] == '1')
sprintf(cp, ne2000ParamTemplate,
	IO_ADRS_ENE,
	......
	ENE_OFFSET);

随后要在Bootable的BSP工程目录下对prjParams.h文件进行修改,将IPMAXUNITS改到你所需要的网卡数目上,比如2,以要求系统支持多网卡并存。

上述的是对BSP的修改,以下我们以深圳盛博公司嵌入式DETH模块为例进行说明应用程序对。SysExpanModule/DETH与Novell公司的NE2000完全兼容,符合标准DETH(以太)协议在板逻辑完成数据包的发送与接收。它提供两个10Base-T接口以满足多网卡使用的需要,但我们可根据实际需要将其设置为相同的MAC地址。

从实际运用的角度上来看,我们要对正在使用的接口进行查询,判断它是否处于正常工作状态。一般的网卡都具有自我判断能力并对其内部寄存器的值进行相应的修改,我们可以通过VxWorks的底层函数sysOutByte()与sysInByte()以查询的方式不断来读取接口的内部寄存器的值。

    sysOutByte(intNum,0xc0);
    enable=sysInByte(intNum+3)&0x04;

当接口出现异常(enable==4),我们将进行接口的切换的。

作为双冗余备份,我们的发送端对于接受方来说应该是透明的。那么我们的两个接口需要的是同一个IP地址,这样就存在了地址冲突的问题。那么我们在使用新的接口之前必须去掉原先的接口的IP并在主机列表中删除它。否则,我们不可能以同一地址来驱动第二个接口。

hostDelete("host table", "192.168.0.1");
ifRouteDelete("ene", 0);
ipDetach(0, "ene"); /*从系统中将第一块网卡配置掉*/
ipAttach(1, "ene"); /*把IP网络层和目的接口链路层建立新的连接*/

/* 如果网络层和数据链路层连接成功设置当前使用的网络适配器*/
ifMaskSet("ene1", 0xFFFFFF00);
ifAddrSet("ene1", 192.168.0.17"); /*配置倒换后的网络适配器的IP地址*/
ifBroadcastSet("ene1", 192.168.0.255");

完成上述步骤之后我们仍然可以通过同一广播发送程序进行发送,接受端只能识别出发送端的路由。笔者进行的测试表明,采用此种切换方式,切换时间可以达到10ms以内,而最终在应用程序中体现出来的正常切换时间在100ms左右,基本可以达到双冗余备份技术的要求(在驱动程序下完成冗余切换大约需要20-80ms左右)。

4结论

利用本文所述的方法,已在某导弹快艇综合导航显控台项目中,成功地实现了VxWorks环境下sExpanModule/DETH的双网卡冗余备份技术,并达到海军作战系统的工作要求。