小谈IP Over PCI 开发

                                                                                                ――

        在本文中,我将前几天开发IP Over PCI 模块时的一些过程和认识与大家共享,另外在文章最后也给出一个简单的Demo模块供朋友们消遣。

        先来说说什么是IP Over  PCI吧。 事情的经过是这样的——我们的通讯系统架构是由一个组插在同一个CompactPci总线上的板卡组成,它们之间可以通过读写PCI空间,进行数据交换(CompactPCIPCI协议的一种扩展,从软件角度讲两者对开发者没什么区别,呵呵)

        由于我们多数板子的Flash存储空间有限,难以存放较为完整的文件系统。所以只想在一个配置有较大Flash的板子上安装Linux系统所需的文件系统,而让其它板子通过NFS方式使用大板上的文件系统。这样做很大程度的节约了各各个 小板的存储空间,可也带来了一个新问题:NFS需要TCP/IP协议栈支持,需要每个板子都有IP地址。

        Thanks GoodnessLinux 内核本身已经含有了对TCP/IP协议栈的支持,不需要我们操心实现了。剩下,我们唯一要做的就是让每个板子都有一个IP地址。要满足这个目的,最直接的方法就是为小板开发一个虚拟网卡,这样有了IP地址,就可以通过TCP/IP协议栈进行通讯的了。

         虚拟网卡的接口要求很简单,只要能够把协议栈送下来的IP包写到CPCI(Compact PCI)地址空间,即从虚拟网卡发送出去了;同时也能将其它虚拟网卡发送到CPCI地址空间的IP包读出来,并送到上层协议栈上。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

                                                  架构图

        

          虚拟网卡的实现我参照LLD中的例子,相信你也能够很快实现。至于从CPCI空间读写数据的实现是体系结构相关的,也没什么难的,不费笔墨了。这里我所以介绍IP Over PCI是希望能抛砖引玉,供大家开阔思路,你不妨想想IP over USB Over serial等等实现方法。

           呵呵,下面给出我做的一个demo 程序<vnetdemo.tar>: IP Over FIFO (注:该程序运行于2.4.18内核,本网站的其它程序也都开发于2.4.18内核,不过移植到2.6内核也不是难事)。

 

        IP Over  FIFO不用解释,也可知道就是用FIFO命名管道来模拟以太网络,我之所以采用FIFO也是为了方便大家在单机上实验,纯用软件模拟――虚拟的网卡,虚拟的线  J

       

         这个程序有两个一样的子文件组成 ,它们各被编译成一个虚拟网卡模块sn0 sn1(我们程序由LDDsnull程序演化而来,其中命名等都保持不变),你只需要分别加载,便可拥有两个虚拟网卡(ifconfig –a可看到它俩,当然你也可以配置它们的IP地址,方法和操作真网卡无异)。 NFS也就可以运行在其上了。

     

          但是要想在同一机器中运行测试这两个网卡,且让它们通讯。就需要在网卡发送时对源地址和目的地址的IP做写手脚 (在实际应用中不同板子之间运行时,不需要如此),其中原因在LDD中的网络驱动程序一章有很完整的解释,大家一定要去看看(开始我漏看了,就一直没能把包从虚拟网卡发出去),检测方法也可照LDD中的ping地址)。

           程序的主干采用了LDDsnull实例的实现,其中不同的地方有三个需要注意:第一点是虚拟网卡无法触发中断,因此IP包的接收(从FIFO中读取IP包)是采用了一个内核线程做轮训读取数据包;第二点是我们利用了两个FIFO管道文件(mkfifomknod命令可生成管道文件)模拟双向传输的网线。每个管道两头都有不同的虚拟网卡读写,只是两个管道读写方相反;第三点是我们需要在内核中读写文件,由于有空间保护问题(有一个断言会判断系统调用的参数地址空间是否在用户空间),因此从内核读写时需要改变空间检测的范围,具体做法是调用前后加上如下语句:

                             fs = get_fs();

                            set_fs (get_ds());

                            系统调用,如sys_open()

                            set_fs(fs);

          就说这些吧!一切真知都来源于实践,希望大家多动脑筋来,多动手。

 

补记:  实例代码运行步骤

              1 执行 make ,编译完成会生成两个vnetdrv1.o vnetdrv2.o两个虚拟网卡模块。

              2 在当前目录下执行 mkfifo fifonet1;mkfifo fifonet2 生成两个用于模拟双向网线的命名管道文件。

              3 执行insmod vnetdrv1.o ; insmod vnetdrv2.o ,注册模块到内核,此刻系统中添加了sn0sn1两个虚拟网卡。

              4 执行 ifconfig sn0 192.168.0.1 ifconfig sn1 192.168.1.2 ,配置网卡 到两个网段。

       5 执行ping -c 2 192.168.0.2 数据将从在两个虚拟网卡间传送。