460 likes | 749 Views
嵌入式 Linux 操作系统. 嵌入式 Linux 引导过程中概念简介. ( 1 ) bootloader 程序 一般来说, bootloader 都分为主机端( host )和目标端( target )两个部分。目标端嵌入目标系统中,在启动之后就一直等待和主机端的 bootloader 程序之间的通信连接。目标端程序需要使用交叉编辑器编译,主机端的使用本地编译器编译。在主机端和目标端之间的通信方式没有规定,一般由 bootloader 程序自己规定。
E N D
嵌入式Linux引导过程中概念简介 (1)bootloader程序 一般来说,bootloader都分为主机端(host)和目标端(target)两个部分。目标端嵌入目标系统中,在启动之后就一直等待和主机端的bootloader程序之间的通信连接。目标端程序需要使用交叉编辑器编译,主机端的使用本地编译器编译。在主机端和目标端之间的通信方式没有规定,一般由bootloader程序自己规定。 但有些bootloader并不需要提供服务端程序,而是使用标准的终端程序作为主机端的连接程序,可以使用Linux下的minicom、kermit或者Windows下的超级终端作为主机端程序。 一般bootloader提供给用户一个交互shell,通过交互式完成自由主机控制目标板的过程,bootloader可以存放在flash中,也可以下载到RAM中,以bootmem方式启动。 CPU总是从一个位置开始启动,bootloader被CPU运行,并为操作系统的运行做准备,一般来说,bootloader的作用有如下几个。
嵌入式Linux引导过程中概念简介 ① 初始化处理器。bootloader会初始化处理器中的一些配置寄存器,如ARM720T体系结构的CPU如果需要使用MMU,就应当在bootloader中进行初始化。 ② 初始化必备的硬件。使用bootloader初始化板上的必备硬件,如内存、终端控制器等初始化就是通过它完成的;用于从主机下载系统映像到硬件板上的设备也是由它完成初始化的。例如,有些硬件板使用以太网传输嵌入式系统映像文件,在bootloader中会使用以太网驱动程序初始化硬件,随后与主机端的程序通信,并完成下载工作。 ③ 下载系统映像。系统映像下载只能由bootloader提供。因为CPU提供的代码无法完成大系统映像的下载工作,而bootloader下载可以很多的自由度,可以指定内核映像和文件系统映像的下载位置。在目标端的bootloader程序中提供了接收映像的服务端程序,而在主机端的程序提供了发送数据包动作——可以通过串口,也可以通过以太网等其他方式发送。发送系统映像结束之后,如果硬件允许,bootloader还可以提供命令将下载成功的映像写入到Flash ROM中。一般bootloader都提供了擦写Flash的命令,为操作带来很大的便利。
嵌入式Linux引导过程中概念简介 ④ 初始化操作系统并准备运行。使用bootloader可以启动已经下载好的操作系统。可以指定bootloader在RAM中或者Flash中启动操作系统,也可以指定具体的启动地址。 (2)嵌入式系统内核 对于使用操作系统的嵌入式系统而言,操作系统一般是以内核映像的形式下载到目标系统中。以Linux为例子,在系统开发完成之后,将整个操作系统部分做成压缩或者没有压缩过的内核映像文件,与文件系统一起传送到目标系统中。通过bootloader指定地址运行Linux内核,启动嵌入式Linux系统;然后再通过操作系统解开文件系统,运行应用程序。 在内核中通常必须的部件是进程管理、进程间通信、内存管理部分,其他部件,如文件系统、驱动程序、网络协议等,都可以配置,并以相关的方式实现。
嵌入式Linux引导过程中概念简介 (3)根文件系统 在嵌入式系统中的“硬盘”概念一般都以ramdisk的方式实现。因为Falsh在断电后还能继续保存数据的设备,但其价格相对昂贵;然而系统中又无法使用像硬盘这样的大型设备,因此,需要长久使用的文件系统数据,尤其是应用程序的可执行文件、运行库等,运行时都放在RAM中。常用的方式就是从RAM中划分出一块内存虚拟成“硬盘”,对它的操作与对永久存储器操作一样。在Linux中就存在这样的设备,称为ramdisk,一般使用的设备文件是/dev/ram0。 ramdisk的启动需要操作系统的支持。bootloader负责将ramdisk下载到与内核映像不冲突的位置,操作系统启动之后会自动寻找ramdisk所在的位置,将ramdisk作为一种设备安装(mount)为根文件系统。
嵌入式Linux引导过程中概念简介 当然,根文件系统不一定使用ramdisk实现,还可以用NFS方式通过网络安装根文件系统。这也是在系统内核中实现的。操作系统启动之后直接通过内核中NFS相关代码对处于网络上的NFS文件系统进行安装。文件系统启动的方式可以在内核代码中编写或者启动时通过参数指定。 (4)重定位和下载 生成了目标平台需要的image文件之后,就可以通过相应的工具与目标板上的bootloader程序进行通信。可以使用bootloader提供的,或者通用的终端工具与目标板相连接。一般在目标板上使用串口,通过主机终端工具与目标板通信。bootloader中提供下载等控制命令,完成嵌入式系统正式在目标板上运行之前对目标板的控制任务。bootloader指定image文件下载的位置。在下载结束之后,使用bootloader提供的运行命令,从指定地址开始运行嵌入式系统软件。这样,一个完成的嵌入式系统软件开始运行了。
嵌入式Linux引导过程中概念简介 (5)Linux内核源代码中的汇编语言代码 任何一个用高级语言编写的操作系统,其内核代码中总有少部分代码时用汇编语言编写的。其中大部分是关于终端与异常处理的底层程序,还有一些与初始化有关的程序以及一些核心代码中调用的公用子程序。 用汇编语言编写核心代码中的部分代码出于以下几个方面的考虑。 操作系统内核中的底层程序直接与硬件打交道,需要用到一些专用的指令,而这些指令在C语言中并无相对应的语言成分。因此,这些底层的操作需要用汇编语言来编写。CPU中的一些对寄存器的操作也是一样,如要设置一个段寄存器时,也只好用汇编语言来编写。 CPU中的一些特殊指定也没有相对应的C语言成分,如关中断、开中断等。此外,在同一体系系统的不同CPU芯片中,特别是新开发出来的芯片中,往往会增加一些新的指令,对这些指令的使用也得用汇编语言。
嵌入式Linux引导过程中概念简介 内核中实现某些操作的过程、程序段或函数,在运行时会非常频繁地被调用,因此,其时间效率就显得很重要。而用汇编语言编写的程序,在算法和数据结构相同的条件下,常比使用高级语言编写的效率要高。在此类程序或程序段中,往往每一条汇编指令的使用都需要经过推敲。系统调用的进入和返回就是一个典型例子,系统调用的进出时非常频繁用到的过程,每秒钟可能会用到成千上万次,其时间效率可谓举足轻重。再者,系统调用的进出过程还牵涉到用户空间和系统空间之间的来回切换,而用于这个目的的一些指令在C语言中本来就没有对应的语言成分,所以系统调用的进入和返回显然必须用汇编语言来编写。 在某些特殊的场合,一段程序的空间效率也会显得非常重要。操作系统的引导程序就是一个例子。系统的引导程序通常一定要能容纳在特定的区域中。此时,这段程序的大小多出一个字节也不允许,所以一般使用汇编语言编写。
嵌入式Linux引导过程 Linux的特点使得它成为适合嵌入式开发和应用的操作系统。对于使用操作系统的嵌入式系统而言,操作系统一般是以内核映像的形式与文件系统一起下载到目标系统中。一个最基本的嵌入式Linux系统从软件的角度可以分为4个层次。 ① 导加载程序bootloader。 ② Linux内核。 ③ 文件系统。 ④ 用户应用程序。 (1)嵌入式Linux引导过程 嵌入式Linux系统的引导过程如下。 ① 理器重新启动后,首先执行启动代码以初始化内存控制器以及片上设备,然后配置存储
嵌入式Linux引导过程 映射。 ② Bootloader把内核从Flash等固态存储设备加载到RAM,然后跳转到内核的第1条指令处执行。 ③ 内核首先配置微处理器的寄存器,然后调用start-kernel,它是与微处理器体系结构无关的开始点。 ④ 内核初始化高速缓存和各种硬件设备。 ⑤ 内核挂载根文件系统。 ⑥ 内核执行init进程。 ⑦ init运行时共享库。 ⑧ init读取其配置文件。 ⑨ init最后进入用户会话阶段。
嵌入式Linux引导过程 在此过程中bootloader的作用是非常重要的。 (2)嵌入式系统中bootloader的作用 嵌入式系统中首先要考虑的是启动问题,当一个微处理器最初启动时,它首先执行一个预定地址处的指令,这个地址处存放系统初始化或引导程序,正如PC中的BIOS。在嵌入式系统中由于没有BIOS,因此将由引导加载程序bootloader实现类似的功能。bootloader代码量虽少,但是其作用却非常重要,而且许多代码与处理器体系结构相关而不具备移植性,因此研究相关技术从而写出针对特定处理器的启动代码对嵌入式系统设计尤为重要。
嵌入式Linux引导过程 嵌入式Linux的bootloader主要作用如下。 ● 初始化处理器; ● 初始化的必备的硬件; ● 下载系统映像; ● 初始化操作系统; ● 启动已下载的操作系统。 总之bootloader负责完成系统的初始化,把操作系统内核映像加载到RAM中,然后跳转到内核的入口点去运行。
嵌入式Linux引导过程 (3)bootloader的操作模式 bootloader一般要实现两种操作模式:自举和内核启动模式。自举模式的主要作用是目标机通过串口与主机通信,可以接收主机发送过来的映像文件,并将其固化在目标机的Flash等固态存储设备中,也可以将Flash中的映像文件上传到主机。内核启动模式允许嵌入式系统加电启动后由bootloader从目标机上的Flash等固态存储设备上将操作系统加载到RAM中运行。一般嵌入式系统中bootloader应能实现这两种模式的切换。 (4)bootloader的基本框架结构 大部分的bootloader依赖于CPU的体系结构和嵌入式板级设备的配置,因此,bootloader可分为两部分:用汇编语言实现的依赖于CPU体系结构的代码stage1和用C语言实现的代码stage2。
嵌入式Linux引导过程 ① stage1的操作。 a.硬件的初始化,包括以下步骤。 ● 屏蔽所有中断; ● 设置CPU的速度和时钟频率。 ● 初始化RAM。 ● 初始化LED或UART。 ● 为加载stage2准备RAM空间。 b.加载stage2到RAM中。 c.设置堆栈指针SP,为执行C语言代码做准备。 d.加载到stage2的C语言入口点。
嵌入式Linux引导过程 ② stage2的基本操作。 ● 初始化本阶段要用到的硬件设备。 ● 检测系统的内存映射。将存储在Flash上的内核映像读到预留的RAM空间之前,先确定这些预留的RAM空间哪些被真正映射到了RAM地址单元。 ● 加载内核映像和根文件系统映像。 ● 设置内核启动参数。Linux2.4.x以后的内核都期望以标记列表的形式传递参数,在嵌入式Linux系统中,通常由bootloader设置的启动参数有ATAG-CORE,ATAG-M EM,ATAG-RAM DISK,ATAG-1NITRD等。 ● 调用内核,即直接跳转到内核的第1条指令地址处执行。
Linux启动流程 基本的启动流程主要分成4个部分。 (1)在系统加电检测结束以后,由BIOS中的代码负责把引导器加载进入机器的内存中,控制权交给引导器。这里又要分成两个部分,因为BIOS只负责装入512个字节的程序,然后把控制权交给这512字节。一般的引导器大小超过512字节,其余部分再由这512字节的代码负责装入。 图5-22 Linux系统启动流程图 (2)引导器负责确定Linux内核的位置,把Linux内核加载进入内存中;同时,确定根文件系统的位置,将根文件系统的镜像加载进入内存中。然后在加载内核
Linux启动流程 的时候给内核传入一些启动参数,用于控制内核执行过程中的一些行为,接下来将控制权交给内核。 (3)内核接管控制权以后,首先解压缩自己,检测设备,加载内部模块。然后根据启动参数挂载根文件系统。挂载完根文件系统后内核启动的第1个进程是init,默认的位置为“/sbin/init”。如果找不到这个可执行文件,就转而启动“/bin/sh”,提供给用户一个人机交互的界面。 (4)init进程启动后查找的第1个配置文件是“/etc/inittab”,这个文件控制init的行动。一般init会首先指定启动等级,然后执行“/etc/ rc.d/rc.sysinit”,同时rc.sysinit−启动脚本启动系统服务进程(如update、syslogd等)、网络和必要的环境变量设置。最后inittab会指定init进程去调用getty打开多个终端控制台,每个终端控制台会执行login,从而出现“login:”的提示符。整个Linux系统启动完成。
从“零”到一套精简的Linux平台 要制作一套精简的Linux系统,首先需要一套完整的Linux开发平台,这套开发平台上必须要有gcc编译连接工具、mkisofs ISO文件系统创建工具。这里选用的是RedHat Linux 7.3。 1.内核的编译和安装 首先介绍x86处理器平台的内核编译与使用,它不需要使用交叉编译平台对内核进行编译。基于ARM处理器的交叉编译内容后续会简单介绍。 这里选用的内核版本号是Linux-2.4.20(可以从www.kernel.org下载)。下载的内核是压缩包,解开压缩包,在源代码目录下使用make menuconfig(也可以使用make config或make xconfig)。 因为需要对Linux进行精简,因此要选择相关的内核选项:
从“零”到一套精简的Linux平台 File systems ---> [*] /dev file system support (EXPERIMENTAL) //使用了devfs文件系统。 [*] Automatically mount at boot Loadable module support ---> [ ] Enable loadable module support //对于固定的硬件平台,把要使用到的驱动都编译进入内核中
从“零”到一套精简的Linux平台 Network device support ---> Ethernet (10 or 100Mbit) ---> [*] Ethernet (10 or 100Mbit) [*] EISA, VLB, PCI and on board controllers [*] AMD PCnet32 PCI support //Vmware软件使用的网卡驱动程序 [*] DECchip Tulip (dc21x4x) PCI support //Visual PC软件使用的网卡驱动程序
从“零”到一套精简的Linux平台 [*] RealTek RTL-8139 PCI Fast Ethernet Adapter support //实际PC使用的网卡驱动程序 这里编译内核的选项还有许多,用户可以根据自己项目的需要选择不同的选项,使制作的Linux平台具有不同的特性。 2.引导器的编译和安装 引导器要能识别ISO9660文件系统,这样它才能在所制作的镜像文件中找到内核和根文件系统镜像,在这里选用的是syslinux自由软件中的一个工具isolinux,版本号为syslinux-2.04(可以在http://syslinux.zytor.com/下载)。 在安装syslinux之前,首先要安装nasm汇编工具,因为syslinux就是靠这个工具编译的。nasm的版本号为nasm-0.98.38(可以在http://nasm.sf.net/下载)。
从“零”到一套精简的Linux平台 安装完nasm工具以后,编译syslinux就可以得到引导器的目标文件:isolinux.bin,这个文件就是在BIOS自检后被加载的代码,负责加载内核和根文件系统。 3.工具软件的安装 一般在嵌入式系统中使用的文件系统,基本的工具集合主要是3个:busybox、tinylogin、uclibc。其中busybox提供各种基本的工具,如cat、ping等;uclibc提供一个精简的C运行库,使用这个库,可以大大减小系统的体积(从1.2MB减小到253KB),但是带来的可能是某些函数不兼容;tinylogin这个工具集合是一个微型的用户登录、认证工具,如addgroup、adduser、login等; 为了防止uclibc带来的不兼容性,可以使用busybox和tinylogin,避免影响一些程序的工作。
从“零”到一套精简的Linux平台 4.启动配置文件的制作 Inittab配置文件是一个固定格式的文本文件,因为精简的Linux平台上使用的init进程是由busybox提供的,与普通Linux上面的systemV init有一定的差异,主要的是busybox提供的init进程不支持启动级别(runlevel)。 Inittab配置文件每一行的格式为: <id>:<runlevels>:<action>:<process>
从“零”到一套精简的Linux平台 5.平台的整合 在平台整合之前,需要建立相应的文件夹,同时要配置好相应的系统配置文件。 系统必须的文件夹为 /bin /sbin /var /dev /proc /lib /home /root /tmp /usr 同时,有些工具放在/usr目录下面,所以在/usr目录下面一般还有如下目录: /usr/bin /usr/sbin /usr/etc /usr/share /usr/lib等 建立好相应的目录以后,将工具复制进入相应的目录中,这样才可以建立一个完整的根文件系统镜像。 建立根文件系统的时候,首先要使用dd命令创建一个32MB大小的文件,然后使用mkfs.ext3把创建的文件格式化成ext3分区格式,最后以loop设备的方式挂载到一个目录下面,把整个文件系统复制到这个loop文件系统上面。 制作好根文件系统以后,使用mkisofs工具合成可启动操作系统镜像,这个镜像就可以作为一套精简的Linux操作系统来使用。 对于dd命令、mkisofs命令的使用,详细内容可查看man page:dd(1)mkisofs(4)。
从“零”到一套精简的Linux平台 6.平台的扩展 在精简的Linux平台上进行扩展是非常方便的,对于平台的扩展主要是两个方面:内核的修改和应用程序的添加。 要修改平台的内核,只要把重新编译过的内核复制到光盘镜像目录的根目录,覆盖掉原来的内核文件,再使用mkisofs工具重新整合操作系统镜像。 要在平台的文件系统中添加一些应用程序,首先要考虑添加应用程序以后,文件系统是否大于ramdisk的容量(这里要考虑系统执行的时候会产生一些临时文件,所以要留有一定的空间),在ramdisk容量够的情况下,解开根文件系统的压缩镜像,使用loop设备的方式挂载到开发系统的文件系统上面。将要添加入的应用程序复制到相应的目录,同时注意是否要复制一些库文件和配置文件。重新压缩根文件系统,最后还是通过mkisofs工具重新合成系统镜像。
从x86平台到嵌入式平台 1.BSP和BIOS 在PC上,操作系统和硬件交互,通过BIOS(基本输入/输出系统)进行,BIOS为操作系统控制硬件提供了一个接口。在嵌入式硬件平台上,由于各硬件平台之间存在着许多差异,当然就不会存在一个通用的BSP(板级支持包),BSP提供与BIOS相当的功能,主要也是对操作系统和底层硬件交互提供一个接口。 BSP的开发是在嵌入式硬件平台开发完成后做的第一件事情,一般BSP不会全部自己写,都是根据其他类似的硬件平台上能使用的BSP源代码进行修改。 2.交叉编译平台 以x86为平台进行Linux的裁减,开发系统也使用x86系列的PC,这样就不需要建立交叉编译平台,在宿主机上能执行的二进制代码,放到目标机器上也是能直接执行的。 而对于ARM、PPC等处理器,指令集与x86的指令集完全不同,在x86平台上能运行的二进制代码,在ARM、PPC平台上不能直接运行,只有通过交叉编译平台,使用源代码编译出目标机器上的可执行二进制代码才能在目标机器上使用。 交叉编译平台是针对CPU的,不同的CPU对应不同的平台,对于硬件电路没有任何关系。交叉编译平台主要包括gcc、ld、ar、strip等工具和在目标平台上的glibc动态库。这样就可以在宿主机器上构件的交叉编译环境下编译目标机器上的操作系统内核、工具软件等。
从x86平台到嵌入式平台 3.驱动程序 对于定制的嵌入式系统硬件平台,大部分驱动程序是不能直接使用的,因为在定制的硬件平台上,板级寄存器的地址、设备的读写地址、RAM/ROM的地址等都不相同。即使是Linux内核支持的设备,也要对其驱动程序源码进行修改才能使用。对于定制的硬件平台一些特殊的专用设备,只能自己来为设备书写驱动。 因为Linux内核源代码中带了各种各样的设备驱动,没有必要每一个字节都自己写,可以根据类似设备的驱动程序,对其进行简单的修改。 4.系统的启动 PC上进行Linux系统精简的工作时,可以使用引导器(如isolinux)来装入Linux
从x86平台到嵌入式平台 内核和根文件系统镜像;在此之前,由BIOS负责转入引导器。而在嵌入式平台上,也可以使用类似的方式,使用一个引导器(如Redboot、Ppcboot等),这些引导器的基本工作原理相同,负责从指定的ROM地址把数据搬运到指定的RAM地址,然后转移控制权。 由于嵌入式系统上比较常见的是使用Flash Memory来存放引导器、操作系统内核和根文件系统。在嵌入式平台上面,内存资源比较紧张,不可能把整个文件系统从Flash Memory复制到RAM中执行,而使用在Flash Memory上面直接可以读写的文件系统jffs。使用这种文件系统,Linux在启动过程中就会又有一些不同的工作,而且对于文件系统的制作也有许多不同的地方。
从x86平台到嵌入式平台 5.平台的整合 在x86上进行Linux系统的精简,最后通过使用mkisofs工具把引导器、操作系统内核以及根文件系统全部集成到一个iso光盘镜像中。 在嵌入式系统平台上,一般采用jtag接口把引导器烧录到Flash Memory中,然后使用Flash Memory上的引导器引导嵌入式系统平台。在引导器的控制下,把操作系统内核和根文件系统镜像都下载到RAM中,然后烧录到Flash Memory的特殊位置上。同时,把这些位置信息让引导器保存起来,这样下一次启动的时候,引导器就直接可以引导Linux系统了。
Linux平台上用户空间程序与内核交互方式 这里将介绍常用的3种用户态进程与内核交互的方式:ioctl、proc、netlinksocket。 1.ioctl 在UNIX系统中,ioctl是设备驱动程序中对设备的I/O通道进行管理的系统调用,所谓对I/O通道进行管理,就是对设备的一些特性进行控制,如串口的传输波特率、电动机的转速等。这个函数主要用于设备驱动中间。 在用户态看来,ioctl的调用方式如下: int ioctl(int fd, ind cmd, …);
Linux平台上用户空间程序与内核交互方式 2.Proc文件系统 Proc文件系统是Linux内核提供的一个虚拟的文件系统,用于让用户空间的进程获取一些内核信息或者配置一些内核的参数,使内核模块以指定的方式工作。一些用户空间的命令(如ps命令)直接读取proc文件系统里面相应文件的信息。 根据内核版本的不同,或者编译内核的时候选择模块的不同,Linux系统执行的时候得到的proc文件系统中的内容将会有所区别。一般一些基本的信息在proc文件系统中都可以找到。
Linux平台上用户空间程序与内核交互方式 在内核模块设计中,和构建/proc文件相关的函数有5个,它们的声明在/linux/proc_fs.h文件中。 (1)struct proc_dir_entry* create_proc_entry(const char* name, mode_t mode, struct proc_ dir_entry* parent) 这个函数以名称name和文件模式mode在目录parent下创建一个规则文件。如果要在根目录/proc下创建,则parent参数用NULL代替。创建成功的话,返回一个指向新建结构体proc_dir_entry的指针,否则返回NULL。另外,这个函数可以支持跨越多层目录的创建。 (2)struct proc_dir_entry* proc_symlink(const char* name, struct proc_dir_entry* parent, const char* dest) 这个函数用于在目录parent下以名称name建立指向dest的符号连接,在用户态,相当于ln -s dest name。
Linux平台上用户空间程序与内核交互方式 (3)struct proc_dir_entry* proc_mknod(const char* name, mode_t mode, struct proc_dir_ entry* parent,kdev_t rdev) 这个函数用于在目录parent下以名称name和模式mode建立一个设备文件,该设备文件在设备rdev下工作,rdev被linux/kdev_t.h中定义的宏MKDEV创建。Mode参数必须包含S_IFBLK或S_IFCHR来创建设备节点。 (4)struct proc_dir_entry* proc_mkdir(const char* name,struct proc_dir_entry* parent) 顾名思义,用来在parent目录下创建名称为name的目录。 (5)void remove_proc_entry(const char* name,struct proc_dir_entry* parent)
Linux平台上用户空间程序与内核交互方式 3.Netlink Sockets Netlink Sockets也是用于在Linux内核空间和用户空间传输信息的方法,它提供了一套双向的内核空间/用户空间交互的方式。对于用户空间程序看来,Netlink Socket就是一套标准的Sockets函数,而对于内核空间模块看来,也有一套方便的函数入口和出口。 现在Linux内核提供的Netlink Sockets协议还进行细分,根据使用侧重点的不同,以前的Linux内核主要分为以下内容: ● NETLINK_ROUTE:接收路由更新信息,可以用来修改IPv4的路由表。
Linux平台上用户空间程序与内核交互方式 ● NETLINK_FIREWALL:接收IPv4防火墙编码发送的数据包。 ● NETLINK_ARPD:用以维护用户地址空间里的arp表。 ● NETLINK_ROUTE6:接收和发送IPv6路由表更新消息。 ● NETLINK_IP6_FW:接收未通过IPv6防火墙检查的数据包(尚未实现)。 ● NETLINK_TAPBASE...NETLINK_TAPBASE+15:是Ethertap设备实例。Ethertap是从用户程序空间对以太网驱动程序进行仿真的“伪”网络通道设备。 ● NETLINK_SKIP:Enskip的保留选项。 ● NETLINK_USERSOCK:为今后用户程序空间协议用保留选项。
Linux平台上网络工具工作框架 Linux是一套功能非常强大的网络操作系统,在最新的Linux内核中,经过研究发现,至少有如下特性。 ① 提供了完整的TCP/IP网络协议栈的实现。 ② 对于其他网络协议(如IPX协议、Appletalk协议、DECnet、X.25协议、IPv6协议等)也提供了很好的支持。 ③ Linux在实现自己的网络协议栈的时候,使用了一套非常灵活的框架:Netfilter构架,这套框架给用户开发网络设备或者开发网络应用等提供了灵活的接口。 ④ 提供了比较完整的QoS支持。 同时,网络上出现的许多自由软件(如动态路由软件zebra,MPLS信令软件rsvpd,Netfilter配置软件iptables,网络工具包Iproute2等)都对某项应用提供了非常完整的实现。如果需要开发自己的设备或者网络应用软件的时候,完全可以参考这些自由软件的体系框架。 下面对Linux中的Netfilter构架、iproute2软件包中的TC工具、动态路由软件zebra和MPLS在Linux下面的工作框架进行简要分析。
Linux平台上网络工具工作框架 1.Netfilter构架和iptables工具 Netfilter是在2.4.x Linux内核版本开始引入的,主要用于代替2.2.x Linux内核版本中的ipchains和2.0.x Linux内核版本中的ipfwadm。 Netfilter提供了一个抽象、通用化的框架,基于Netfilter框架的功能有包过滤、NAT、数据包处理等。Netfilter框架包含以下3部分。 ① 为每种网络协议(IPv4、IPv6等)定义一套挂载点,其中,IPv4协议定义了5个挂载点,这些挂载点在数据包流过协议栈的几个关键点被调用。在这几个点中,协议栈将把数据包及挂载点标号作为参数调用Netfilter框架。 ② 内核的任何模块可以对每种协议的一个或多个挂载点注册钓子函数,实现挂接,这样当某个数据包被传递给Netfilter框架时,内核能检测是否有任何模块对该协议和挂载点进行了注册。若注册了,则调用该模块的注册时使用钓子函数,这样这些模块就有机会检查、修改、丢弃该数据包或指示Netfilter将该数据包传入用户空间的队列。
Linux平台上网络工具工作框架 ③ 那些排队的数据包是被传递给用户空间的异步地进行处理。一个用户进程能检查数据包,修改数据包,甚至可以重新将该数据包通过离开内核的同一个钩子函数中注入到内核中。 图5-25所示为Netfilter构架内部结构图,从图中可以看出Netfilter架构为IPv4提供了5个钩子函数的挂载点,挂载在其上的钩子函数会在如下情况中被调用。 ● NF_IP_PRE_ROUTING:在完整性校验之后,选路确定之前; ● NF_IP_LOCAL_IN:在选路确定之后,且数据包的目的是本地主机; ● NF_IP_FORWARD:目的地是其他主机地数据包; ● NF_IP_LOCAL_OUT:来自本机进程的数据包在其离开本地主机的过程中; ● NF_IP_POST_ROUTING:在数据包离开本地主机,准备进入网络之前。
Linux平台上网络工具工作框架 内核模块可以对一个或多个这样的钩子函数进行注册挂接在挂载点上,在数据包经过挂载点时,这些钩子函数被调用,从而模块可以处理这些数据包,并向Netfilter返回如下值以决定这个数据包的命运。 ● NF_ACCEPT:继续正常传输数据包; ● NF_DROP:丢弃该数据包,不再传输; ● NF_STOLEN:模块接管该数据包,不要继续传输该数据包; ● NF_QUEUE:对该数据包进行排队(用于将数据包给用户空间的进程进行处理); ● NF_REPEAT:再次调用该钩子函数。 在IPv4的IP层代码中,有一些带有NF_HOOK宏的语句,如IP的转发函数ip_forward( )中有如下语句: N_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, dev2, ip_forward_finish);
Linux平台上网络工具工作框架 2.iproute2软件包中的TC工具 Linux内核从Kernel 2.1.105就开始支持QoS,其核心机理是在输入/输出接口,对不同数据进行调度和处理,即流量控制(TC)。这套系统支持分类、优先、共享、输入/输出流量限制等,可以与专用的带宽管理系统相媲美。 TC只有在输入检测和输出队列两部分对数据报进行控制。输入检测仅仅是丢弃数据包,而输出队列则是对数据报进行排队、丢弃、延时及设置优先级。
Linux平台上网络工具工作框架 3.Zebra软件的介绍 Zebra是一个TPC/IP路由软件,支持BGP-4、BGP-4+、OSPFv2、OSPFv3、RIPv1、RIPv2和RIPng。它的发行遵循GNU通用公共许可协议,可以运行于Linux以及其他一些UNIX变体操作系统上。Zebra是那些系统最新的发行版本中的路由软件。最新版本的Zebra以及文档可以从GNU Zebra(www.zebra.org)网站上下载 一般的动态路由软件采用一个进程,实现动态路由信令的管理和操作系统内核RouteTable的管理,而Zebra采用了更加模块化的系统构架,它使用多个后台进程互相合作,管理路由表。 Zebra动态路由软件能够支持多种动态路由协议,每一种动态路由协议,Zebra都使用一个后台服务进程负责解析该协议的数据包和判断网络拓扑的变化情况。 图5-27 Zebra的体系构架图 ripd用于处理RIP协议,ospfd用于处理OSPFv2协议,bgpd用于处理BGP-4协议,ripng用于支持ripng协议,ospf6d用于支持OSPFv3协议,而zebra用于接收各种协议服务程序的路由修改信息进行综合判断,再通过rtnetlinksockets接口和Linux内核进行通信,改变内核的RouteTable。
Linux平台上网络工具工作框架 4.MPLS在Linux下面的工作框架 图5-28所示为Linux平台下MPLS平台的架构,MPLS在Linux下面主要包括3个部分。 ① Linux内核里面的MPLS协议栈。 ② 在用户态,运行在IP层以上的信令软件。 ③ 信令软件和MPLS协议栈的接口程序。
Linux平台上网络工具工作框架 不同的MPLS路由器之间通过RSVP信令进行交互,如果要建立LSP或者在LSP上映射流量,信令交互的结构肯定是改变标签转发表,这就需要通过MPLSAdm这个接口程序来实现协议栈上数据的修改(相关的软件包都可以在网站http://dsmpls.atlantis.ugent.be/下载到)。 在入口MPLS路由器(LER)上面,要实现IP层到MPLS层的映射关系,这里就会使用到netfilter构架、路由表等对入口流量进行分类,然后在MPLS协议栈上打上标签。同时,在Linux内核里面支持比较完整的QoS体制,能够对于不同类别的流量建立不同的队列,采用不同的算法实现对流量的控制和流量的整形。 在核心MPLS路由器(LSR)上面,对于MPLS数据包只要检查其标签,然后根据标签转发表,去除源标签,打上新标签,发送到相应的QoS队列中去,实现对数据包的转发。 在出口MPLS路由器(LER)上面,实现了一个和入口MPLS路由器相反的一个过程,去除MPLS包中的MPLS标签,重新回复IP头,把回复的IP包发送到MPLS域以外的网络中去。