VxWorks操作系统在实时嵌入式网络通信中有着广泛的应用,在VxWorks下实现FSR(鱼眼路由,Fish-eye Routing)协议过程中探索了对VxWorks内核路由表的访问机制,并实现了一种利用route socket机制对内核路由表的访问方法,达到了对内核路由表操作控制的目的。 VxWorks是美国风河公司推出的优秀的实时嵌入式操作系统,它在航空航天、军事和民用通信、工业控制等诸多领域有着广泛的应用。VxWorks操作系统中集成了完整的TCP/IP协议栈,尤其通过组件windNet(tornado 2.2以前版本)和platform NE(tornado 2.2以后版本)可以基本实现现有常用的网络协议,其中包括点对点协议PPP、路由协议ospf、简单网络管理协议SNMP、以及要在本篇文章中用到的router stack等等协议,因此在网络通信领域有着很强的应用能力。 我们在开发FSR(鱼眼路由)的开发过程中,需对VxWorks的内核路由表进行操作,包括路由表维护和路由发现,为了解决这些问题,我们对TCP/IP协议栈的路由表内核实现进行了分析,研究了VxWorks下的路由表内核访问机制,分别通过route socket机制和内核路由表的一些实现方法来完成了对内核路由表的访问,达到了对内核路由表的控制和操作。 1 Router Stack对内核路由表的访问机制 风河公司在以上所说的组件里分别提供了WindNet Router Stack1.1和WindNet Router Stack 1.2,该路由协议栈通过一个router socket接口来完成对内核路由表的操作,用户在开发自己的路由协议并想集成到路由协议栈中去的时候,就要通过该路由协议栈提供的socket接口和消息来完成对路由表的访问并监视路由表的变化。此外,用户还可以采用第二种方法,即利用routeEntryLib库提供的函数来完成协议的注册、路由表的操作以及对内核路由消息的相应处理等操作。在此处主要介绍前一种方法,即采用route socket方法实现对内核路由表的访问。 Router Socket给用户提供了一个和内核路由进行消息交互的插口,内核有一个进程在等待处理这些消息,并根据不同的消息类型及消息所携带的数据对路由表采取不同的处理方法。此外,内核还及时把路由表的变化情况通过消息的形式发往外部进程,如果我们在程序中同样设置一个外部进程,通过接收这些内核传来的消息就可获得路由表路由的变化情况,从而达到对路由表监测的目的。 2 利用Route Socket对内核路由表的访问方法 如上所述,使用route socket利用消息对路由表进行操作就要知道各种消息类型及实现方法,在router socket里提供的主要消息有:RTM_ADD(向路由表中增加路由)、RTM_DELETE(从路由表中删除一条路由)、RTM_CHANGE (改变路由表中一条路由的参数)、RTM_GETALL(获得路由表中符合条件的路由)等。下面以向路由表中增加一条新记录为例来说明具体的实现过程。 在该例中,假设本机地址为192.168.11.2,现向其路由表中增加一条目的地址为192.168.10.0、网关为192.168.11.1、子网掩码为255.255.255.0,权重值为6,跳数为3的记录。首先定义一个消息结构体struct aRtSockMsg theRtSockMsg: 成员:struct rt_msghdr msgHdr及char appendBuf [512];该结构体中struct rt_msghdr为消息头结构,在route.h中定义,appendBuf数组里放置向路由表中写入的数据,数据的内容在数组中从0字节开始从前向后的顺序依次为:目的地址(Socket地址格式,16字节)、网关地址(Socket地址格式,16或18字节)、子网掩码(socket地址格式,16字节)。现定义目的、网关、掩码的socket地址格式如下: struct sockaddr_in so_dst,so_gate,so_ mask; 给这三个变量赋值如下分别为:AF_INET,htonl(inet_addr("XXXX")),16然后根据以上所述顺序把三个变量的内容拷贝到appendBuf数组中去; 现在该设置消息头的内容了,主要内容设置如下: 代码 - theRtSockMsg.msgHdr.rtm_type=RTM_ADD;
- theRtSockMsg.msgHdr.rtm_addrs=theRtSockMsg.msgHdr.rtm_addrs|RTA_DST|RTA_GATEWAY|RTA_NETMASK;
- theRtSockMsg.msgHdr.rtm_msglen=sizeof(struct rt_msghdr)+48;
- theRtSockMsg.msgHdr.rtm_pid=RTM_ADD_RESPONSE;
- theRtSockMsg.msgHdr.rtm_inits=theRtSockMsg.msgHdr.rtm_inits|RTV_HOPCOUNT|RTV_WEIGHTIRTV_ROUTETAG;
- theRtSockMsg.msgHdr.rtm_rmx.rmx_hopcount=3;
- theRtSockMsg.msgHdr.rtm_rmx.weight=100+6;
- theRtSockMsg.msgHdr.rtm_rmx.routeTag=1;
整个消息结构组建完毕,现在用以下函数向内核路由表发送该消息: 先定义一个raw_socket套接字,然后用send函数发送: int routeSock=socket(PF_ROUTE,SOCK_RAW,0); i=send (routeSock,(char *)&theRtSockMsg,sizeof(struct rt_msghdr)+48,0); 3 接收内核的反应 消息发送以后,内核会根据消息携带的内容对路由表进行操作,然后把操作的结果发送回来,我们只需在程序中设置一个任务对内核发送回来的消息进行监视,就可以知道操作的结果,具体实施如下: 首先定义并启动一个任务routeSockProcess负责处理从内核传来消息的函数,其实现函数如下: 本文探讨了在VxWorks操作系统下使用route socket对内核路由表的访问机制,通过对内核返回消息的分析和处理,可以达到和路由表进行交互的目的,从而完整地实现对路由表的操作和监控,上述方法已成功应用于我们自己开发的路由协议中。当然对内核路由的访问还可以通过其他方式,比如使用内核实现的源代码函数等,限于篇幅,其他方法将在其他文章中探讨,不再在此赘述。 代码 - void routeSockProeess()
- { ……
- for(;;)
-
-
- if(count>0)
- {
- rtmH=(struct rt_msghdr *)buf;
- cmd=rtmH->rtm_type;
- switch(cmd)
- {
- case RTM_ADD:
- int t=rtmH->rtm_errno;
-
- ……
- case RTM_DELETE:
- ……
- default:break;
- }
- }
- }
- }
4 总结
|