发明的详细说明
在附图中,图4显示了由英特尔公司制造的一个网络处理器(IXP1200)的体系结构,在本发明中将使用这种类型的网络处理器。本领域技术人员将能够理解,本发明也适用其他相似和相关的处理器,特别是网络处理器。IXP1200网络处理器包括一批微处理机(或子系统),它们被连接在IX总线接口上。微处理机可由微代码动态编制程序。微处理机拥有无需StrongARM核心处理器的帮助,自动执行指令,经由总线接口访问系统组件的能力。要利用微处理机来进行网络处理,这就要求改进软件体系来支持微处理机。
因此,本发明将软件组件添加在图3所示的传统软件环境中,并给在微处理机上运行的微代码定义了一个表接口,使微处理机能够唯一地处理数据平面通讯,从而实现了对传统网络处理进程的重要性能的改进。特别的是,图5显示了一个本发明的软件框图,该软件收集合适的信息,激活微代码处理机,它利用放置在一个微代码路由表中的信息来做出路由和转寄决定。
图5中所示的流程1a-c代表控制和管理通讯的路由。流程1a表示了封包进入系统时的路由流程。流程1b表示了用路由协议更新路由表的流程,作为新的路由并被加入到路由表中。流程1c表示了在需要时被发送给其他通讯设备的路由响应流程。流程2a同样显示了网络处理器处理数据平面通信(所有的通信经过该系统,而并不以该系统本身为目的地)的流程。当网络处理器软件体系使用了微处理机上运行的微代码系统来处理数据平面通信,为了做出正确的路由决定,微代码必须已经访问了路由信息和端口信息以及任何在控制和管理层上的传送服务所需要的,并通常已经由传统的软件体系进行了处理的,特定的标记或性质。微代码系统使用了一个微代码路由表来实现正确的信息平面通信的路由。一个转寄表管理器负责识别来自于标准路由表的路由信息,来自于TCP/UCP/IP堆栈的信息,以及任何用来生成微代码路由表的特定标记要求。
转寄表管理器对一个微代码路由表的实现,部分是基于LC-Tries压缩的等级化数据结构的原理,以及基于Stefan Nilsson和Gunner Karlsson所做的工作,在题为《使用LC-Tries的IP地址搜索》的论文中对其公开,日期为1998年7月2日,在此通过参考合并。下面给出了一个LC-Tries压缩的理论性示例,虚拟IP地址查阅表如下:
表1
表项号 |
虚拟地址 |
0 |
0000 |
1 |
0001 |
2 |
00101 |
3 |
010 |
4 |
0110 |
5 |
0111 |
6 |
100 |
7 |
101000 |
8 |
101001 |
9 |
10101 |
10 |
10110 |
11 |
10111 |
12 |
110 |
13 |
11101000 |
14 |
11101001 |
表1与图6a中所示的树形图相关联。为了用于图解说明,虚拟地址表示从二叉树的根节点到任意单独终端叶节点的路径,其中“0”代表在任意特定节点左转,而“1”代表右转。举个例子,第6表项包括一个虚拟地址100。这表示初始时从根节点向右转,而之后在接下来两个节点向左转。这代表了从根节点到终端叶节点的路径,它对应于图6a中所显示的二叉树的第6表项。另外在表1中的表项以二进制数排序,使得在做出任何右转之前要先做出同样多的左转。换句话说,从表顶部到底部的表项经过了整理,以左转为优先,在每一种情况下“0”优先于“1”出现。
树型结构压缩的第一个步骤包括路径压缩,籍此移除尽可能多的内部节点(例如,不包含一个终端叶节点的节点)。这种压缩的结果如图6b所示,2,13和14号表项分别依照跳跃值(Skip)2和4被压缩。注意在路径的压缩期间,并不是所有的内部节点都被移除。在路径压缩期间,有些叶节点不是源于同一父节点,拥有至少两个这样的最终分支叶节点的内部节点不能够被移除。这种方法有效的移除了在任意到达一个特定的叶节点(或者是它最近的兄弟节点)的单一路径中必须经过的,并且是唯一经过的派生节点。这种方法有效的压缩了树结构的稀疏区域。
压缩的第二步骤,叫做层次压缩,它有效的压缩了树型结构的密集区域。这种方法是将当且仅当一个给定节点的所有兄弟节点都是内部节点的时候,将该节点的所有兄弟节点全部移除。层的移除在一个分支因数(Branch)中反映,它可以被表示为2的乘方(2Branch),因为一个节点通常有两个分支。因此,Branch代表了被移除的层数,而2Branch表示一个被移除节点的子节点数目。被压缩的二叉树的层和路径在图6c中显示,而表2中的数据则说明了如何处理该二叉树。
表2
节点号 |
BRANCH |
SKIP |
指针/表项号 |
虚拟地址 |
0 |
3 |
0 |
1 |
-- |
1 |
1 |
0 |
9 |
-- |
2 |
0 |
2 |
2 |
00101 |
3 |
0 |
0 |
3 |
010 |
4 |
1 |
0 |
11 |
-- |
5 | 0 | 0 | 6 | 100 |
6 |
2 |
0 |
13 |
-- |
7 |
0 |
0 |
12 |
110 |
8 |
1 |
4 |
17 |
-- |
9 |
0 |
0 |
0 |
0000 |
10 |
0 |
0 |
1 |
0001 |
11 |
0 |
0 |
4 |
0110 |
12 |
0 |
0 |
5 |
0111 |
13 |
1 |
0 |
19 |
-- |
14 |
0 |
0 |
9 |
10101 |
15 |
0 |
0 |
10 |
10110 |
16 |
0 |
0 |
11 |
10111 |
17 |
0 |
0 |
13 |
11101000 |
18 |
0 |
0 |
14 |
11101001 |
19 |
0 |
0 |
7 |
101000 |
20 |
0 |
0 |
8 |
101001 |
节点号值的确定是通过从根部开始,由顶层到底层,在每一层中从左到右计数每一个节点来实现的。因此根节点的子节点从左到右被赋予节点号1-8,而第9号节点对应于表1中第0号表项(根节点)的左侧子节点的左侧子节点,以此类推。如上面所讨论的,Branch的值等于在当前节点和它的子节点之间由于层次压缩所移除的层数,而2Branch等于该节点的子节点数目。此外,Branch的数目也等于需要被用来唯一地识别一个特定节点的所有给定的子节点的虚拟地址的位数。同样,如上所述,Skip值等于在路径压缩期间被移除的内部节点数。指针/表项号的值有两种用处。如果该特定的节点是一个内部节点(Branch≠0),那么指针/表项号代表该特定节点的左派生节点号。在这种情况下,指针/表项号是指向表2中另一个表项的一个指针。如果该特定节点是一个叶节点(Branch=0),那么指针/表项号的值表示表1中一个表项的表项号(为了方便,表1的虚拟地址信息被输入表2的最后一栏,对应表1中所出现的每一个表项)。当然,纯粹的内部节点没有一个外部虚拟地址与其相关联,而这种情况在表2的虚拟地址栏中就由“--”来表示。
要概念性的说明对压缩的LC-Tries进行搜索的方法,请参考下面使用表2中的信息在图6c的压缩了的LC-Tries中对二进制数串“10110111”所进行的搜索。它起始于根节点(节点号0),Branch值是“3”而Skip值是“0”。这表示在根节点下已经有三层树结构被移除,有23(8)个派生节点被移除。没有节点被跳过。这意味着搜索数字串的首先三位包含了被压缩移除的信息。搜索数字串的前三位(“101”)等于十进制数5,将该值加在根节点存储在指针/表项号栏中的值(“1”)上,生成表中下一个表项的节点号(“6”)。由于Branch不等于“0”,在指针/表项号中的值是一个指针,而不是一个根节点表项数。因此,在表2中的LC-Trie压缩信息将搜索进程导入被压缩的LC-Trie中的下一个节点。针对表2中第6号节点的信息重复执行这些步骤,生成Branch“2”和Skip“0”。因此,搜索数字串的4-5位(下两位)等于十进制数“2”,将该值加到节点号6那一行的指针/表项号栏中的数值(“13”)上,得到“15”。因为Branch仍旧不等于“0”,这表示在LC-Trie的下一步骤中指向第15号节点。表2显示第15号节点的Branch值等于“0”,它表示这是一个叶节点。第15号节点的指针/表项号等于“10”,并且虚拟地址是“10110”,它是与搜索数字串“10110111”最匹配的前缀。
本发明的首选实现方法使用了Microware Systems公司的OS-9操作系统,Berkeley Standard Distribution(BSD)4.4版TCP/UDP/IP堆栈,RIP和OSPF路由协议,以及英特尔IXP1200网络处理器的Microware微代码解决方案库。这些组件被用于本发明的开发和实现,本领域技术人员将能够理解,本发明能适用任意的操作系统(实时的或非实时的),任意协议堆栈,任意路由或寻址协议,以及任意在网络处理器微处理机上运行的软件。
转寄表管理器(FTM)的优选实施例由一个FTM程序组成,它在Microware Systems公司的OS-9实时操作系统,或者Linux上运行。如图5中所示,FTM程序与不同的网络处理器软件组件进行接口,来提取完成数据通讯所需要的所有信息。这一信息被存储在一个叫做转寄表的微代码IP路由表中,该表是基于上面所揭示的LC-Trie压缩算法的一个特定的具体实现而建立的。为了数据封包寻径的目的,用于查询转寄表的FTM程序能够由一个低级别驱动程序通过命令行选项来执行。该低级别驱动程序能够与FTM程序在同样的处理器段运行,或者在IXP1200网络处理器的一个完全分离的微代码子系统上运行。事实上,FTM程序本身可以在一个与网络处理器不同的处理器上运行,或者它也可以在网络处理器上运行。本发明的方法可以被用在一个有多个计算机元件的计算机系统上,其中该方法是在一个主计算机元件和一个从计算机元件之间实现。使用网络处理器作为一个示例,核心处理器将包括主计算机元件,而微处理机将组成从计算机元件。然而,本发明没有这样进行限制。多个计算机元件可以在同一个微处理器上,在不同的微处理器上,或者在计算机系统中的不同计算机设备上。
无论如何,通过使用FTM程序,低级别驱动程序能够在没有整个网络软件体系的帮助下,实现数据空间的路由寻径,并且这种方法充分减少了与数据空间通讯管理相关的管理费用。
紧接着是FTM程序的初始化,它包含图5中所示的转寄表管理器的主要特征,查询系统以确定现存的所有IP地址,路由信息,以及层2的机器地址-例如,以太网的介质访问控制(MAC)地址。然后应用程序分配内存给两个表,并按照本发明的方法用当前信息填充这些表。表被存储在任意可由微处理机访问的内存区域。应用程序还为系统的不同组件注册了所有类型的通知,从而确保表保持稳定,并由系统的网络堆栈维持其更新。
由应用程序分配的两个表共同包含图5中的微代码路由表。该表包含一个搜索树,其内部使用了上面所述的LC-Trie路径和层次压缩算法,以及下一跳跃表。在本发明的首选实施例中,这两个表包含一个确定的表项数,并且在初始化分配之后不能够被动态调整大小。FTM程序包含命令行选项,来改变这些表在初始化时使用的默认大小选项。
一般说来,在收到一个IP封包的情况下,FTM程序的作用是读取封包目的地IP地址,并在之后搜索表,以便分配下一个跳跃的目的地地址。这可能是该封包的最终目的地,或者只是另一个路由器的地址,该路由器能够在稍后将该封包转寄往它的最终目的地。FTM程序进行的搜索将会导致三种可能的结果,这取决于与被搜索地址相关的表的状态:(1)没有找到通向终点的路径;(2)找到路径,但是层2的信息无效;(3)找到路径,并且层2的信息有效。
在第一种情况中,应用程序仅能停止处理该封包,或者将该封包传送回网络堆栈进行处理。后一种情况是优先的,在这种情形中,系统能够发布一个报错消息,返回给源主机,说明没有为封包找到路径。在第二种情况中,这种情形出现得最频繁,即在下一个跳跃地址指向一个没有MAC信息的本地以太网上的一个路由器,或由一个异步传送模式(ATM)网络连接实现来该路由器连接且没有建立回路。在这种情况下,FTM程序会把封包传回系统的网络堆栈,来解决层2的信息问题。例如,在以太网上,系统将会广播一个地址解析协议(ARP)请求。如果系统能够使层2的信息有效,系统通知FTM程序更新表,用于转寄以后的封包。第三种情况是最期望的最终结果。在这种情况中,FTM程序在转寄表中查找所有必需的信息,以便立即通过正确的端口将封包发送到正确的目的地。
详细说来,FTM程序包括几个命令行选项,用以在程序中调用控制其操作。用于呼叫FTM程序的协议包括一个呼叫命令FTM[<选项>],其中的选项包括
-t[大小,LC-Trie的大小(缺省值=100,00表项)]
-n[大小,下一跳跃表的大小(缺省值=50,000表项)]
-f[数字,填充因数(缺省值=0.50)]
-r[数字,根节点分支因数(缺省值=16)]
-c[激活高速缓存(对IXP1200,缺省状态为打开)]
-d[增加/降低调试级别(5级)]
-i[在IXP1200上运行(只能在运行Linux时设定)]
-p[秒,ARP表查询时间间隔(缺省值=30)]
将LC-Trie搜索表缺省设置为100,000表项。这个参数没有最大值;唯一的限制是可用内存的数量。每一个表项占据4字节,因此整体缺省内存使用量是400,000字节。大致估计搜索表所需要的空间是IP路径最大值的2至3倍,再加上根节点分支因数所占据的任何附加空间(下面会详细解释)。同样,如这里下面所解释的,在表中的填充因数和路径的组织会对搜索表所需的内存数量产生巨大的影响。
将下一跳跃表占据量缺省设置为50,000表项。与搜索表一样,下一跳跃表的实际大小也仅仅由可用内存量限制。每一个表项占据16字节,总体缺省占用800,000字节的内存。路径的总数加上这些路径所涉及的唯一路由器数量,大致等于下一跳跃表所需的大小。例如,如果路由表包含5条到达路由器A的路径,以及3条到达路由器B的路径,那么在下一跳跃表中的总表项数等于10(5条路径到A,加上3条路径到B,加上到达A和B的路径)。
填充因数是一个优选的参数,它使搜索的速度增加,作为代价,需要生成一个较大的LC-Trie搜索表。填充因数是一个在0和1之间的数字,它表示百分率。缺省因数是.5,或者是50%填充因数。要理解填充因数的作用,需要先回想起前面所讨论的LC-Trie的理论实现问题,分支因数表示层次压缩量。Branch的值等于被跳过的层数,而2Branch等于在层次压缩期间任意两个节点之间被移除的节点数量。因为执行中假设每个节点有两个子节点,表示一个字节的信息,也就是说,只有当向左或者向右,所到达的预留层的子节点的数量等于2乘方时,才可能移除一个层。因此,参见图6c,根节点包含23(8)个子节点,子节点中所有被预留的节点包含21(2)个或者22(4)个子节点。层次压缩的值来自于在LC-Trie中从一个层到另一个层的移动记录,它表示一个内存访问。在一个未压缩的Lc-Trie中,搜索数串中的每一位代表LC-Trie的一层,并因此,代表一个内存访问。层次压缩群将搜索数串的几位合起来,并允许一个内存访问一次处理搜索数串中的几位信息,从而减少需要完成搜索所必需的内存访问次数。因此,这证明层次压缩对提高路由性能来说很重要。然而,每个节点正好需要2Branch个子节点的事实将会妨碍层次压缩,并且因此妨碍对减少搜索的好处的利用。考虑到层次压缩可能不满足每个节点有正好2Branch个子节点的需要,填充因数允许加入人造的虚拟节点。例如,如果两个层的压缩可以移除具有6个子节点的节点,压缩通常情况下不发生。填充因数允许增加两个虚拟节点,使子节点的数量达到8,这样就能够进行压缩了。赋予填充因数的值包括一个阈值级别,用于确定是否用虚拟节点填充一个层。在一个先前的示例中,一个有6个子节点的层是75%完整的(其中8个子节点组成一个完整的层)。如果填充因数等于.75或者更小,那么该层被两个虚拟节点填充,并进行压缩。因此,填充因数越大,压缩的就越少。这将会导致搜索时间更长,但是能够预留搜索表中的空间,不用生成虚拟表项。填充因数越小,搜索的越快,但是将会导致搜索表变大。需要经过实验来确定填充因数的最佳设置,它取决于任意特定具体实现方法中的准确环境。
根节点分支因数由一个应用于根节点的填充因数的特定实现组成。根节点分支因数使根节点分支拥有2k个子节点,其中k等于根节点分支因数。根节点分支因数的缺省值是16。
高速缓存值提供了保证,确保在高速缓存中存储的搜索LC-Trie表和下一跳跃表的任何改变都能够立即被转移到适当的永久存储位置。OS-9操作系统在检测到自己正在一个IXP1200网络处理器上运行时,会自动激活高速缓存。本发明的Linux系统应用中需要将表放置于一个非高速缓存的内存中,这使得高速缓存选项无效。然而,在一些具体实现中,在高速缓存中存储表,或其它可以从永久内存中直接查看表格的处理器部分中,在这些具体实现中,高速缓存选项可以被设定,以避免数据失效的问题。
当前FTM程序包括5个调试级别。调试选项能够在命令行被指定1到5次,来选择所期望的不同级别。
IXP1200选项用于Linux,OS-9自动检测它是否在一台IXP1200网络处理器上运行。设定这个选项必须考虑到在下一跳跃表中的适当的端口号配置。在IXP1200上的端口号有不同的分配。
ARP表查询选项也是用于Linux系统。因为FTM应用软件的Linux系统应用中不接收关于ARP层2信息变化的直接通知,这一选项允许FTM程序在一个设定的时间间隔内查询以太网ARP高速缓存。OS-9系统应用中使用了总线来探听网络堆栈的监控,这将缓和对ARP高速缓存进行查询的需要。
FTM程序拥有对来自于应用程序外部的某些信号做出响应,使应用程序完成某些任务的能力。一个SIGINT信号使应用程序打印当前的LC-Trie搜索表和下一跳跃表。SIGUSR1和SIGUSR2信号引起调试级别的变化,前一信号提升调试级别,而后一个信号降低级别。如果FTM程序被初始化为不激活调试,那么对级别的提升将会激活调试级别1。如果在FTM程序命令行中输入两个-d选项,那么对级别的提升将会激活调试级别3。如果调试级别被设定在5(最高级别),额外的提升级别的信号将不起作用。类似的,如果调试级别是0,那么降低级别的信号将会被忽略。
下面的讨论描述了搜索表和下一跳跃表的设计和实现。特别是,这些信息涉及了FTM程序如何接收到建立表所需的信息,表的数据结构,和建立和搜索该表所用的算法。
FTM程序所使用的表存储在内存中,该内存被FTM程序和数据封包的转寄实现程序所共享。封包转寄程序仅能读取表,而不能对表做出改动。FTM程序能实现所有的管理功能,比如在表中增加或删除表项。
同样,FTM程序所使用的微代码路由表包括两个部分:(1)LC-Trie搜索表;和(2)下一跳跃表。LC-Trie搜索表包含了FTM程序用于存储和搜索IP地址的主要数据结构。LC-Trie搜索表是非常高效的数据结构,来实现IP地址的最长可能的前缀匹配,该IP地址被用来定位一个数据封包的转寄地址。LC-Trie的每个节点在内存中由一个搜索表中的4-字节表项来表示。正如前面的理论实现中所揭示的,在搜索表中的每一个表项包括一个分支因数(Branch),一个跳跃值(Skip),和一个数值,该数值代表一个指向LC-Trie自身的指针,或者代表到下一跳跃表中的一个转移量(表2中的指针/表项号)。因此,每4-字节LC-Trie结构如下:
5比特 7比特 20比特 |
分支因数 |
跳跃值 |
Lc-Trie/下一跳跃转移量 |
同样,分支因数表示在层次压缩期间所移除的层的数量,而2分支因数表示被移除的子节点的数量。跳跃值表示任意的路径压缩。因此,FTM程序在一个搜索步骤中能够处理Branch+Skip位的搜索串。LC-Trie/下一位转移量(指针/表项号)表示在搜索表中与搜索串相匹配的下一表项的位置(如果Branch≠0),或者表示转移到包含转寄IP地址的下一跳跃表的表项的转移量(如果Branch=0)。
搜索LC-Trie的目的是找到在下一跳跃表中的表项,该表项拥有和搜索树相匹配的最长的前缀数位。引入的数据封包将会被发送至存储在这个表项中的转寄IP地址处,该地址将会最直接地将数据封包路由至它的最终目的地。然而,需要重点解释的是,并不必须将整个搜索串与一个目的IP地址匹配。所需的只是与地址的网络部分相匹配。例如,如果在表中有一个路由,它对应于有18位网络掩码的IP地址172.16.192.0,它将会同IP地址172.16.224.14或IP地址172.16.120.39的网络部分相匹配,而不是同任一地址严格匹配,如下表所示。
十进制 二进制(网络掩码位) |
172.16.192.0/18 |
10101100 00010000 11000000 |
|
172.16.224.14 |
10101100 00010000 11100000 |
172.16.120.39 |
10101100 00010000 1111000 |
接下来,转到下一跳跃表,这张表包括将一个数据封包转寄至另一个主机/路由器所需的实际信息。对LC-Trie搜索表的搜索返回一个转移量到下一跳跃表。实际的下一跳跃表项由一个16字节表项组成,它的格式如下:
转移量0 |
IP地址 |
转移量4 |
掩码长度 |
标记 |
下一跳跃转移量备份 |
端口号 |
转移量8 |
端口指定 |
IP地址出现在前4个子节,并包括了该表项的整个第3层的地址。掩码长度占据5位,表示与该表项相关的网络掩码的位数。换句话说,IP地址的右首部分用于识别与地址相关的网络,而地址中剩下的部分识别在这个网络上的特定的主计算机。掩码长度确定了在将IP地址转换成一个二进制等效数字之后,用于识别网络的位数。标记的设定能够使掩码长度表项无效。如果标记位显示该表项是一台主计算机,那么就不使用掩码长度,因为所有的主机表项设定掩码长度是32位。如果需要的话,掩码长度位的长度位数可以被增至7位,来用于处理IPv6地址。
标记区域占据5位,然而,只有数位0和1被使用,剩下的数位被预留下来。数位1是网络位。如果该数位被设定(等于1),这表示该表项是一个网络路由。在这种情况下,在下一跳跃表中需要多一个跳跃,以便为该表项获取合适的层2的信息(即,以太网的MAC层信息),当前下一跳跃表项的端口指定区域将包括一个转移量,它转移到存储正确层2信息的下一跳跃表项。如果数位1没有被设定,那么该表项是一个主机路由,而端口指定区域将包括该表项的层2地址信息。数位0是一个有效位。如果数位被设定,那么在端口指定区域中任何层2信息都是有效的。如果数位没有被设定,这代表层2信息有问题,它或者是丢失了,或者是过期了。如果网络位被设定,那么有效位是不重要的。有效位仅与层2信息的有效性相关,而并不转移到下一跳跃表中。
下一跳跃转移量备份区域占据14位,并被用在搜索算法在LC Trie之下运行太靠下的情况中。这种情况出现,是因为LC-Trie搜索算法试图找到与搜索串匹配的最大数位前缀,而且仅当LC-Trie搜索算法到达一个叶节点的时候,搜索才会结束。在极少的情况中,搜索算法能够找到一个正确的匹配,仅能在理论上判别一个匹配可能是最佳匹配,但在实际用途中,它可能是一个不能接受的匹配。
在IP地址应用中,需要考虑网络掩码长度,因为它影响搜索算法。
在IP地址搜索中,搜索目标不会正好与数位最大前缀相匹配,而是与一个表项的网络掩码中的位数相匹配。基于下面表3考虑一个示例:
表3
十进制 二进制 |
搜索串 |
172.16.130.44 |
10101100 00010000 10000010 0101100 |
|
表项1 |
172.16.0.0/16 |
10101100 00010000 00000000 00000000 |
表项2 |
172.16.192.0/18 |
10101100 00010000 11000000 00000000 |
该表显示了一个IP地址172.16.130.44的搜索串,后面是它的二进制等价数。该二进制等价数是通过将十进制IP地址的每一部分转换成8位二进制数而获得的。该表包括两个表项,出于本例的目的,表项1是表项2在LC-Trie中的父节点。表项1拥有16位的网络掩码长度,而表项2有18位的掩码长度。当然,表项1和表项2的前16位匹配搜索串。然而,最大前缀匹配将会出现在搜索串和表项2之间(全部二进制数字串的前17位匹配)。因此,LC-Trie搜索算法将会通过表项1,将搜索串与表项2相匹配。这产生了一个不期望的结果,表项2的网络掩码是18位,而表项2和搜索串只有17位匹配。因此,由搜索算法提供的匹配并没有识别正确的网络。然而,父节点表项(表项1)的网络掩码长度位数字,并不与搜索数串的前16位匹配。在这种情况中,正确的匹配是父节点表项(表项1),或是子节点表项(表项2),由搜索算法来找出。这种情况的出现是因为搜索算法正在设法匹配最大的前缀。要处理这种情况,一旦搜索算法到达LC-Trie的底部,并且表项和搜索数串之间相同的位数不等于至少是网络掩码长度的位数,算法返回查看数结构,尝试寻找一个符合该标准的匹配。正是因为这个原因,下一跳跃转移量备份中存储了当前表项的父节点的转移量。这种情况出现在实际应用中的极少实例中,最突出的是缺省路径。因为一个缺省路径的网络掩码长度经常比任意其他路径都要小,所以缺省路径将总是所有派生路径的一个网络掩码长度前缀匹配。
端口号区域占据8位,它提供给FTM正确的信息,用来同网络处理器的其余部分进行通讯。端口号的配置一般具有两种形式,它由运行FTM程序的微处理机和网络处理器其它部分之间接口的特性来决定。如果IX位被设定,那么FTM程序正在使用IX总线(见图4),并且端口号区域的配置如下所示。
位7 位6 位5 位4 位3 位2 位1 位2 |
IX | |
MAC号 |
单元号 |
端口号包括IXP1200接口MAC号和单元号。如果该数位没有被设定,这表示该接口不是在一个IX总线上。在这种情况中端口号的配置形式如下。
位7 位6 位5 位4 位3 位2 位1 位2 |
IX | |
接口指针 |
数位0-5包括接口的接口指针号,它被用于在运行FTM程序的微处理机和网络处理器其它部分之间进行通讯。当然,这个区域的格式能够并且将会不同,以适应其他的,新形成的,寻址协议和相关的信息。
端口指定区域由8字节组成,并被用于存储下一跳跃转移量,或是存储层2的信息,这取决于标记的设定。如果标记位被设定,表示该表项是一个网络路径,端口指定区域包含了转移到包含有层2信息的下一跳跃表的转移量。在这种情况中,下一跳跃表的表项配置形式如下。
转移量0 |
IP地址 |
转移量4 |
掩码长度 |
标记 |
下一跳跃转移量备份 |
端口号 |
转移量8 |
下一跳跃表转移量 |
转移量12 |
未使用 |
可能将层2的信息存储在当前的表项中,然而,由于实际的目的,在下一跳跃表中,为网络路径层2的信息而创造一个单独的表项已经被证明更有效率。在实际中,下一跳跃表中的几个表项拥有同样的下一跳跃层2地址信息的现象频繁出现。将该地址单独存储在一个单独表项内,从而使得表项的更新更为简单。如果地址改变,系统仅需要查找并改动单一表项,而不需要搜索每个表项来找出所有需要更新的表项。
如果标记没有被设定,代表该表项是一个主机路由,并且端口指定区域将会包括该表项的层2地址信息。在这种情况中,下一跳跃表的表项配置形式如下。
转移量0 |
IP地址 |
转移量4 |
掩码长度 |
标记 |
下一跳跃转移量备份 |
端口号 |
转移量8 |
字节1 |
字节2 |
字节3 |
字节4 |
转移量12 |
字节5 |
字节6 |
字节7 |
字节8 |
在以太网的情况中,端口指定区域包括6-字节MAC地址。对于一个ATM网络,端口指定区域包括一个经过编译的VCI/VPI电路号码。无论如何,FTM程序都没有曾经对这个数据进行过处理和解译。它总是被当作是8个单独的字节,来防止这些处理器出现相关的endian问题,这种问题不允许对数据进行不加限制的分割。
端口指定区域的长度和功能可以不同,如上所述,它能作为一个opaque型数据区域,能够存储一大批专门的封包处理参数。例如,端口指定区域也能够包含与服务参数,加密处理参数,多协议标签交换(MPLS)标记,或虚拟局域网(VLAN)标记,等等类似物相关的信息。
下面的讨论描述了FTM程序的结构和核心功能。FTM程序主要负责建立,搜索和维护搜索表和下一跳跃表。这包括一些功能,像添加,更新,以及基于新的路由信息和路由信息的更改而对表项进行删除的功能,还有对层2网络信息的维护。为了执行这些功能,FTM程序需要通过操作系统同网络堆栈进行通讯。由于FTM程序在不同的操作系统上运行,用于实现FTM程序的协议也因操作系统的变更而变更。为了使这些变更最小化,FTM程序在两种截然不同的组件中实现。第一种,一个独立于操作系统的应用程序接口(API),它实现一系列表操作的核心功能。第二种,一个操作系统特定组件,它将来自于系统其它部分的,实现核心功能所需要的信息翻译成适合于核心功能的形式。
处理主要的搜索和下一跳跃表的核心功能由操作系统请求,并包括以下程序。一个FTMAddRoute函数添加一条路径到搜索/下一跳跃表,并使用了四个参数:(1)一个目的地IP地址——与一条路径相关联的目的地网络或主机,它被转化为指向一个常规in_addr结构的一个指针;(2)网关IP地址——与路径相关的下一跳跃地址,也是一个指向in-addr结构的指针;(3)网络掩码长度,是一个整型数;以及(4)端口号,有效的端口号在0-255之间。FTMAddRoute函数有可能失效,或者是因为被添加的路径已经存在,或者是因为搜索/下一跳跃表已经满了。
一个FTMDelRoute函数被用来从搜索/下一跳跃表中删除一条路径。该函数除了不需要的端口号之外,使用了相同的参数。只有在要被删除的路径不存在的时候,FTMDelRoute函数才有可能失效。
一个FTMAddMAC函数被用来将opaque型数据填充在端口指定区域内,这些数据一般由层2信息组成。FTM程序不解译MAC信息,而只是简单的存储该信息,用于在被查询时作为返回。该函数使用了三个参数:(1)目的地IP地址——该IP地址同层2的MAC信息相关,是指向一个in_addr结构的一个指针;(2)数据指针——一个指向层2信息的无符号字符指针;以及(3)大小——数据指针所指向的层2信息所用的字节数,当前被限制为8字节。如果存储层2信息所需要的超过8字节,数据指针将会指向一个有足够空间存储该数据的表格的索引。当下一跳跃表已满,或者被传到函数中的层2信息超过8字节时,FTMAddMAC函数失效。
一个FTMDelMAC函数被用于删除层2信息。该函数所需的唯一参数是与层2信息相关的目的地IP地址。该函数实际上并没有删除层2信息,只是将该表项屏蔽为无效。如果在下一跳跃表中没有发现目的地IP地址,或者如果该表项已经无效了,该函数失效。
一个FTMQuery函数被用于实现对搜索/下一跳跃表的搜索。该函数有一个参数,它以IP地址的形式转换进入该函数,作为一个指针指向一个in_addr结构。该函数返回三种可能结果中的一种:(1)错误,如果没有到该IP地址的路径存在;(2)错误,如果路径存在但是无效;(3)成功,当一个附带有效的层2信息的IP地址被找到时。在第一种情况中,返回一个空值。在最后一种情况中,返回的是指向下一跳跃表的表项的指针。
一个FTMQueryRT函数被用来实现对搜索/下一跳跃表的搜索,它能够区分一个FTMQuery函数命令的前两种结果。换句话说,FTMQueryRT函数能够被用来区分路径不存在,还是存在一条路径,但是却包含无效的层2信息。如果路径不存在,FTMQueryRT返回一个空值。如果路径存在,该函数返回一个指向下一跳跃表的指针,在这一点用户能够检查有效位,来确定该表项是否包含有效的层2信息。
在操作系统的特定方面,FTM程序需要在控制和管理平面上同网络堆栈进行通讯,以便访问更新和维护搜索及下一跳跃表所需的信息,或者发送信息请求。同样,程序的这一部分也是因操作系统而异的。提及OS-9系统,OS-9系统使用了BSD(加州大学柏克利分校软件)Unix-型路由域套接口,来发送和接收进出网络堆栈的配置信息。FTM程序打开一个路由套接口,并简单的读取所有消息,但是仅仅只注意两种消息,即,RTM_ADD和RTM_DELETE消息。一旦FTM检测到了引起它注意的消息,它就解析该消息的正文,并使用适当的核心函数(FTMAddRoute,FTMDelRoute,FTMAddMac,FTMDelMac)来更改搜索/下一跳跃表。
在OS-9中,无论何时,当一个新的路径被添加到路由表中时,或是第2层信息更新时,由SPIP(IP协议层)发送一个RTM_ADD消息。在任何一种情况中,该消息将拥有一个RTA_DST区域,它包含与该表项相关的IP地址。该消息还有一个RTA_GATEWAY区域,它将能够区分是添加一个新路径,还是更新第2层信息这两种情况。RTA_GATEWAYSOCKADDR的AF_FAMILY区域的值将被用来区分这两种任务。如果AF_FAMILY区域等于AF_INET,就添加一个路径。如果该值等于AF_LINK,那么就添加一个第2层表项。下面的例子说明了这两种命令行指令,它们后面是由OS-9生成的RTM_ADD结果消息。Command-route add-net 192.168.9 172.16.5.88 255.255.255.192类型:RTM_ADD
标志:RTF_UP RTF_GATEWAY
地址掩码:RTA_DST RTA_GATEWAY RTA_NETMASK
RTA_DST:10010000c0a809000000000000000000
SIN_FAMILY:AF_INET
SIN_ADDR:c0a80900
RTA_GATEWAY:10020000ac1005580000000000000000
SIN_FAMILY:AF_INET
SIN_ADDR:ac100558
RTA_NETMASK 08000000ffffffc0
SIN_LEN:8
SIN_ADDR:ffffffc0
Command-arp-s 192.168.3.141 00:11:22:33:44:55
类型:RTM_ADD
标志:RTF_HOST
地址掩码:RTA_DST RTA_GATEWAY
RTA_DST:10020000c0a8038d0000000000000000
SIN_FAMILY:AF_INET
SIN_ADDR:c0a8038d
RTA_GATEWAY:1412030006000600001122334455000000000000
SDL_LEN:0x14
SDL_FAMILY:AF_LINK
SDL_INDEX:3
SDL_TYPE IFT_ETHER
SDL_ALEN:6
SDL_DATA:001122334455
FTM程序把层2信息作为一个opaque型数据。在SDL_DATA区域中的MAC地址00:11:22:33:44:55被作为一个无符号字符型数组,它包括6字节的数据。这样就允许FTM程序处理所有类型的数据,而不需要特别知道在一个系统中每个接口的特殊类型。
在OS-9中,无论何时,当一个路径被从路由表中删除时,或是一个层2信息被删除时,SPIP送出一个RTM_DELETE消息。该消息中包含的数据,除了包含RTM_DELETE中的TYPE档案之外,与RTM_ADD消息中所包含的数据相同。
Linux和OS-9实现的不同之处在于,Linux不支持BSD路由域套接口。Linux使用了一种类似技术叫做网络连接套接技术。然而,网络连接套接技术,只能够接收路径的添加和删除。这就要求用别的方法获得层2信息。
特别的是,FTM程序在命令行中使用的最后选项设定了一个查询时间间隔,用于检查在以太网ARP高速缓存中的新表项。查询允许FTM应用程序获知ARP高速缓存何时改变,这个信息被用于同一个Unix域套接机制相结合,使ATM网络子系统添加或删除层2信息。该机制使用了网络连接套接概念,将网络连接RTM_NEWNEIGH和RTM_DELNEIGH消息发送至/TMP/ATMPROXY Unix域套接口。FTM程序打开套接口,读取消息,并调用适当的核心函数(FTMAddMac或FTMDelMac)来更改第2层信息。
当新的路径被添加到系统中时,Linux系统生成一个RTM_NEWROUTE消息,而当一个路径被删除时,生成一个RTM_DELROUTE消息。下面的例子说明了两种类型的命令行指令,它们后面是由Linux生成的结果消息。Command-route add-net 192.168.9.0 netmask 255.255.255.192gw 172.16.5.88
类型:RTM_NEWROUTE
网络掩码长度:26
族:AF_INET
RTA_DST:00080001c0a80900
RTA_LEN:8
RTA_TYPE:RTA_DST (1)
DATA:c0a80900(192.168.9.0)
RTA_GATEWAY:00080001c0a80900
RTA_LEN:8
RTA_TYPE:RTA_GATEWAY (5)
DATA:c0a80312(192.168.3.18)
RTA_OIF:0008000400000002
RTA_LEN:8
RTA_TYPE:RTA_OIF(4)
DATA:2(接口指针)
Command-route del-net 192.168.3.141 netmask 00:11:22:33:44:55
类型:RTM_DELROUTE
网络掩码长度:26
族:AF_INET
RTA_DST:00080001c0a80900
RTA_LEN:8
RTA_TYPE:RTA_DST(1)
DATA:c0a80900(192.168.9.0)
RTA_GATEWAY:00080001c0a80900
RTA_LEN:8
RTA_TYPE:RTA_GATEWAY(5)
DATA:c0a80312(192.168.3.18)
RTA_OIF:0008000400000002
RTA_LEN:8
RTA_TYPE:RTA_OIF(4)
DATA:2(接口指针)
接下来,伪码被用于揭示首先建立LC_Trie和下一跳跃表,并在之后搜索该表的程序。建立表的程序通常是直截了当的。第一步包括从系统路由表中找回所有当前路由信息。该信息封包括所有的IP地址,来自于层2表的任意MAC地址信息,以及等等类似信息。为系统中的每一条路径生成一个下一跳跃表项,没有特定的顺序。同样,如果该表项是一个网络路径,则生成两个下一跳跃表项,一个包含IP地址,另一个包含层2地址信息。
接下来根据IP地址对下一跳跃表项进行排序,完全相同的表项被删除。在一个网关服务器是到多个路径的下一跳跃的情况中,会出现完全相同的下一跳跃表项,网关的主机信息只需要在下一跳跃表中存储一次。同样,如果与一个特定表项相关的层2信息已经在ARP高速缓存中,这可能导致相同的信息。如果一个表项的IP地址和掩码长度与另一个表项的相匹配,这个表项就被判断为是重复的。在表项重复的情况下,有有效的层2信息的表项优先于有无效信息的表项而被预留下来。
下一步骤包括使用参照表1中表项所描述的方法,根据二进制IP地址来对表项进行排序。可以使用任何常规的排序方法,包括基于像快速排序这样的排序算法的标准比较法,或也可以使用一种基数排序算法。一旦表项被排序,识别基础向量和这些基础向量的前缀向量就是一个简单的任务了。一个前缀向量是一个表项,它的二进制IP地址拥有一个位数至少与表项掩码长度相同的前缀,完全被包含在另一表项的掩码长度位前缀之内。此外,一个前缀向量将包含一个在LC_Trie中的内部节点,而基础向量将包含一个终端叶节点。例如,参见图3,表项1是一个前缀表项,其基础向量存储在表项2中。当然,有可能表项2也会是某些其他基础向量表项的前缀向量。因为表被排序,一个前缀表项将会紧跟着它的基础向量表项,从而可能产生一条这样的表项链。这样的表项链可以被连接到一起,使得可以简单地从一个基础向量开始。从最大掩码长度到最小掩码长度通过每个前缀表项,从而穿过整个表项链。表项链中的连接对应于下一跳跃表中的下一跳跃转移量备份区域。同样,在某些特殊情况中,LC-Trie搜索在树结构中进行的太靠下时,它允许在树结构中向上回溯。
在实际建立LC-Trie搜索表之前的最后步骤中包括对下一跳跃表中的每一条网络路径表项进行的更新,该表项有一个指针指向在下一跳跃表中包含该IP地址层2信息的表项。同样这减少了在几个表项使用同一个MAC地址的情况下,对MAC层2信息进行更新的复杂程度。由于MAC信息存储在下一跳跃表的一个单独表项内,如果MAC信息改变,只有这个表项需要更新。否则,每次MAC信息改变时,都必须线性搜索下一跳跃表的表项,已找到所有受影响的表项。
为了在构造进程期间避免和正在进行的LC-Trie表搜索发生冲突,LC-Trie在一个单独的内存区域进行初始化构造,并在完成之后LC-Trie被拷贝覆盖在原LC-Trie之上。下面,基于Nillsson&Karlsson的工作,显示了用于实现一个递归函数的虚拟代码,这个递归函数被用来从一个叫做Base的IP地址项目表中建立一个叫做LC-Trie的LC-Trie搜索表。
Build(int first,int n,int pre,int pos)
{
if(n==1)
{
LC-Trie[pos]={0,0,first};
return;
}
Skip=ComputeSkip(pre,first,n);
Branch=ComputeBranch(pre,first,n,skip);
Offet=AllocateMemory(2^Branch);
LC-Trie[pos]={Branch,Skip,Offset};
p=first;
for bitpat=0to 2^Branch-1
{
k=0;
while(Extract(pre+Skip,Branch,Base[p+k])==bitpat)
k=k+1;
Build(p,k,pre+skip,Offset+bitpat);
p=p+k;
}
<dp n="d30"/>
}
基于表Base中的表项分支(或子区间)的递归处理,LC-Trie表(LC-Trie)被从上到下建立。Build函数传递4个整型参数:first——来自于被Build函数处理的表Base的表项系列的第一表项号码;n——被Build函数处理的表项系列的表项数;pre——被Build函数处理的表项系列的任意共同前缀的位数。以及pos——在表LC-Trie中,用于分配一个表项的第一个可用的位置。
要说明一个LC-Trie搜索表的建立,请参考上面的Build函数在表1中表项上的执行情况。函数的初始调用形式如“Build(0,15,0,0)”,其中初始调用包括表1中的所有15个表项。第一条if语句处理仅有一个表项调用Build函数的情况,在这种情况中,在表LC-Trie中生成一个引导节点。因此由这个if语句生成的所有叶节点(或终端)的分支和跳跃值都是零。而Nilsson和Karlsson揭示了一种带有非零跳跃值的叶节点,实际中在有完整IP地址的情况下这种现象是不会出现的。
如果有不止一个表项,控制程序进入下一个执行区,来计算Skip和Branch的值。Skip值由一个ComputeSkip函数来计算,该函数检查子系统中的第一个和最后一个表项,寻找一个共同的前缀位,在任意这样的前缀中的位数就包含了Skip值。在Build函数的初始化调用中,在表1中的15个表项中没有共同的前缀,因此,Skip值等于零。
Branch值由一个ComputeBranch函数来计算,它检查在子系统中的所有表项,来确定前缀的最大位数,它忽略了任何共同前缀,包含了位数的所有可能值。使用该函数针对表1中所有表项的第一次调用来进行说明,这里没有需要忽略的共同前缀。因此,开始第一位出现的所有数值是(0,1),对表项的前两位的检查显示在表项中出现的所有可能的前两位数值是(00,01,10,11)。继续用这种方式,列出所有数值的前3位,但是没有列出前4位。因此,Branch值是3。
Offset的数值由一个AllocateMemory函数来计算。该函数的结果(Offset)是一个内部指针,指向在搜索表LC-Trie中与当前内部节点相关联的下一跳跃表项。换句话说,AllocateMemory返回表2的指针/表项号栏中的指针部分。考虑到在当前节点和下一跳跃内部节点之间的Branch个层,以及2Branch个内部节点已经被移除,AllocateMemory函数设定Offset的值以反映它在压缩的LC-Trie中的新节点位置。接下来,Branch,Skip,和Offset值被分配给当前搜索表表项(LC-Trie[pos])。通过例证的方法,第一次通过Build函数,由于23个内部节点被移除,Offset将等于1(见表2,第一行)。这反映了在图6a中是第7节点(从0开始)的内部节点,现在在图6c所示的压缩LC-Trie中是第一节点。这里减少了8(23)个节点。将Branch,Skip,Offset的值分配到搜索表中的当前位置,从而在压缩的LC-Trie中设定了这条从根节点到第一内部节点的新路径。
接下来的代码部分包含了递归调用,它建立了表项中的逐渐增多的较小子区间。这些代码设定了一个计数变量p等于first,它保存了在递归调用之前的第一表项的数值。一个for循环执行2Branch次循环,每次处理一个被移除的节点。循环将一个局部变量设定为零,并在之后调用一个while循环来计数带有每一个可能的共同前缀的表项数量,或者设定其位数。While循环使用了一个Extract函数,它返回一个整数,该整数与一个表项的一个预先确定的部分等价。该函数的调用形式如Extract(p,b,s),其中函数返回的整数等于起始于位置p的字符串s的b位。之后针对每一个组合调用Build函数一次。
为了说明递归代码部分,使用了一个针对所有表项调用Build函数的示例,第一次进入该部分的p被设定为0。For循环从0增至23-1,或8次循环(每一次处理该3位的8种可能数值中的一种)。计数值K被设为0,而while循环被执行。While循环将求出Branch位数(在这种情况中是3),开始于第(p加k)个表项(在这种情况下是0)的pre加Skip(在这种情况下是0)位置处,并在之后将该数值同bitpat(在这种情况下是0)作比较。While循环的第一个循环将会从表1中提取第0(000)个表项的前三位,它就等于bitpat。计数值k被增加,而循环重复进行,这次提取第1(000)个表项的前三位,它也等于bitpat。计数值k被增加到2,而while循环提取第2(001)个表项的前三位,它不等于bitpat。然后递归调用Build函数,用于一系列与bitpat匹配的表项(在第一表项是第0号表项的情况下,所建立的函数调用,可能是针对k-1个表项,而不是k个表项)。当递归调用返回后,计数值p的值增加k,for循环继续。在这种方法中,一次建立LC-Trie的一个分支。
首选实现方法与虚拟代码实现方法有所不同,在这种方法中,为了调节根节点分支因数,该因数经常被使用,在LC-Trie中的第一表项需要有一个跳跃值0。
正如所提到的一样,LC-Trie表被建立在一个单独的内存区域,并在之后被拷贝到现存的LC-Trie表之上。拷贝操作从表底部到顶部,一次处理一个表项。这避免了在拷贝期间锁定表的需求。因此,搜索和拷贝可以在同一时间进行。搜索算法很少反向移动搜索表,因此,一个搜索操作很可能只在搜索表的新旧区域之间移动一次。而这有可能导致搜索失败和封包丢失,这一现象出现的几率很小,小到足以证明在拷贝期间,不对表格进行禁止搜索的锁定是有好处的。
要在搜索表中添加一个新表项,需要将该表项附加到表中的一个空闲表项上,并在之后用上述同样的方法重新建立表。要删除一个表项,仅需要把被删除的表项标记为空闲表项即可,并在之后重新建立表。然而,由于移除一个表项不会影响到剩余表项的顺序,排序步骤可以被省略。
下面的虚拟代码揭示了对LC-Trie压缩的搜索表进行搜索的程序。在本发明的首选实施例中的程序(以及下面所透露的程序)都用C代码和IXP1200微代码来实现。本领域技术人员将能理解本发明并非局限于此,而能够用其他语言实现。
FTMQuery(ip)
{
if(hopent=Getent(ip))
{
if(hopent.flags&Flags_Net)
{
hopent=nexthop[hopent.pro_spec.nhop];
}
if(hopeent.flags&Flags_PSV)
{
return(hopent);
}
}
return NULL;
}
Getent(ip)
{
node=LC-Trie[0];
<dp n="d34"/>
Pos=node.skip;
Branch=node.branch;
Offset=node.offset;
While(Branch!=0)
{
node=LC-Trie[Offset+Extract(Pos,Branch,IP)];
Pos=Pos+Branch+node.Skip;
Branch=node.branch;
Offset=node.offset;
}
hopent=nexthop[Offset];
bitmask=hopent.ipaddr^ip;
if(Extract(0,hopent.masklen,bitmask)==0)
{
return hopent;
}
Offset=hopent.nexthop;
While(Offset!=NoPrefix)
{
hopent=next[Offset];
if(Extract(0,hopent.mask.len,bitmask)==0)
{
return hopent;
}
<dp n="d35"/>
}
return NULL;
}
搜索开始于对FTMQuery核心函数的调用,它尝试为IP地址ip寻找一个匹配。FTMQuery函数调用Getent函数,该函数实际处理搜索。Getent函数,如果成功的话,它在变量hopent中返回的是在下一跳跃表中同地址ip相匹配的表项。如果Getent不成功,它在变量hopent中返回的是一个NULL值。因此,如果Getent函数返回一个ip地址,控制程序进入FTMQuery的if语句中。在这一点上FTMQuery需要检查两种情况。第一,Getent检查在下一跳跃表中标记区域,来确定该ip地址是否是一个网络入口。如果是,在下一跳跃表中做出一个以上的跳跃来获得层2信息。第一条if语句处理这种情况。第二种情况包括检查在下一跳跃表中的标志区域,来确定在hopent中的该ip地址是否有效。如果它有效,FTMQuery成功返回hopent,否则,则返回一个NULL值。
同样,Getent函数实际搜索表LC-Trie,为IP地址ip寻找一个匹配。首先,该函数载入根节点信息,联系表中的第一表项来设定Pos(或Skip),Branch,和Offset的值。接下来,Getent执行一个while循环来搜索表LC-Trie,直到它到达一个终端叶节点,例如,一个Branch等于0的节点。要说明表2中数值的使用,假设Getent被调用用于搜索ip地址10111。根节点信息被载入,设定Pos=0,Branch=3,和Offset=1。函数提取ip地址10111的前三位,或101,它等于十进制的5。将Offset的值(表2中的指针/表项号码)加到这个值上得到6(5+1),它确定了在表2中要读取到节点中的下一表项(第6号节点)。之后Pos当前值被增加到Pos值+Branch+node.skip的现值。这样就给Pos赋值为3(0+3+0),这意味着现在,Pos个数位可以被Getent忽略。Branch和Offset的值可以被分别设定为2和0(在表2中的第6节点的数值)。由于Branch不等于0,While循环再次执行。Extract提取出在ip中下面剩下的,也是最后的两个数位(11),并返回其十进制等价数3,之后将该值与表2的第6表项中的Offset值相加。因此,该节点被赋值为3+13=16。第16号节点的Branch值是0,它使得while循环终结。在这一点,Getent函数已经确定了一个同样的匹配:第16号节点的虚拟地址同地址ip正确的匹配。然而,在实际应用中,Getent需要进一步检查该匹配,以确定它所找到的是否是最佳匹配。
在Getent中接下来的代码段是while循环,它确定了在ip和hopent之间的匹配是否符合在hopent中的掩码长度位数。这可以通过进行排他操作或是在两个字符串上进行操作,并在之后对比if语句的结果而实现。如果掩码长度位数匹配,那么Getent已经找到了一个匹配,并返回hopent(下一跳跃转移量)。
接下来的代码部分处理没有匹配,或是没有明显匹配的情况,Getent反向查看二叉树寻找匹配。该代码段开始设定Offset,用于从hopent开始沿二叉树反向的第一表项。一个while循环被执行,只要Offset还是一个有效的数字,它重复先前代码段的功能。如果找到一个匹配,Getent返回hopent,否则它会继续尝试寻找。如果没有找到匹配,Getent返回NULL。前面所述的揭示了在微处理机上运行的FTM程序的结构,相关表的格式,以及建立和搜索该表的方法。然而,FTM程序并不能独立实现功能。网络处理器的结构中需要有一种方法,用于核心处理器同微处理机的接口。例如,如果当FTM程序不能够处理一个数据封包,而将该封包传送给核心时,或是当本发明的首选实施例中,构造和维护表的FTM程序部分在核心处理器上运行时,同时程序的搜索部分在微处理机上运行。在任一情况中,都需要一个接口,用于在上述计算机元件之间提供通讯。
下面描述了由IXP1200微代码所实现的接口优选实施例,它被用于StrongARM核心。这个接口提供了将一个以太网和/或ATM驱动程序写入任意操作系统所需的框架,该操作系统在核心上运行。当然,这并不是本发明的局限,本发明和该接口可以使用任何常规的或相似的网络。FTM程序提供了大批在数据平面上的标准通讯,然而,有些实施例中需要在核心和微处理机之间进行通讯。这种通讯包括主控制和管理平面通讯,FTM程序,连同设置和初始化信息以及数据平面通讯一起,进入核心处理器。
核心驱动程序有两种初始化职责。第一是确认硬件已经被正确的初始化。第二是给微处理机提供所需的设置参数。这种设置参数由一个CSR(设置和状态注册器)程序被提供给微处理机。附录A包含一个“C”语言结构,它描述了接口CSR。
在接口初始化之后,核心仅负责高级缓存描述符的管理。所有的MAC和物理层处理进程由微处理机通过FTM程序进行处理。
核心处理器和微处理机使用缓存描述符来交流被传输/接收的数据以及所需的任意控制信息的位置。以太网和ATM驱动程序各自分配和维护它们自己的一系列缓存描述符。这些描述符集合进一步被分为单独的传输缓存描述符和接收缓存描述符集合。因此有四个截然不同的组:以太网接收;以太网传输;ATM接收;和ATM传输。虽然这四个集合被单独维护,但它们都是用同一种基础数据结构。唯一的不同之处在于每一个组的状态区域位的定义不同。缓存描述符的一般格式如下:
Offset 0 |
下一缓存描述符 |
Offset 4 |
控制/状态 |
端口号 |
Offset 8 |
数据长度 |
预留 |
Offset 12 |
数据大小 |
预留 |
Offset 16 |
数据位置 |
Offset 20 |
用户数据 |
Offset 24 |
预留 |
Offset 28 |
每个缓存描述符涉及一个单一完整的封包。每个驱动程序最少必须有一个传输和一个接收缓存描述符,然而在实际应用中会需要更多。所需要的数量取决于有多少端口被激活,以及所期望的封包等级。如果核心驱动程序或微处理机不能够得到一个空闲的缓存描述符,性能将受到影响。描述符的最大数量仅受到可用内存量的限制。这里强烈推荐将所有的缓存描述符或者定位于非高速缓存的内存中,或者不止一个地出现在一个单一高速缓存线路上。
不同缓存描述符队列的内存位置由CSR设置。有两种类型的链表队列。第一种类型使用了IXP推/拉式队列。八个可用的推/拉式队列中的三个被要求用于以太网或ATM接口。除了一个等待最终核心处理的传输缓存描述符清单之外,这些队列还保存着树表的传输和接收缓存描述符的清单。在插入或移出这些队列时不需要锁定,因为这是硬件提供的功能。第二种类型的队列被用于传输和接收队列。这必须保持一个FIFO排序,所以推/拉式队列不适用。为提供快速的插入和删除,队列中的每一个元素都有一个头指针和一个尾指针。为了保证连贯性,在访问这些来自于核心驱动程序的队列之前,必须使用CAM(条件访问模块)锁定机制来锁定尾指针。
每个描述符包含一个微处理器从不修改的用户-定义区域。这个区域可以被用于核心驱动程序想做的任何事情。例如,数据指针可以指向一个数据区域,它内部包括某些其他结构比如一个mbuf。在封包传输之后,驱动程序可能需要将这个内含结构返回给系统。用户数据区域提供了一个便利空间用于存储这个结构。
下面描述了接收缓存描述符的格式,其一般形式如下所示。核心驱动程序负责分配和初始化接收缓存描述符,它的组件也在这里下面有所描述。
下一个缓存描述符区域用于生成一个描述符链,通过识别被处理链中的下一缓存描述符,该描述符链被核心处理。
控制/状态字区域包含了与该缓存描述符所描述的实际数据相关的某些错误信息,以及某些特征信息。这个字的结构是多样的,它取决于该信息是否是在一个以太网或ATM网络上接收/传输的。
控制/状态字(以太网)
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
| | | | |
T | | |
FC |
FR |
OV |
CR |
SH |
LG |
MC |
BC |
控制/状态字占据16位,所有的预留位将被初始化为零。
从数位15到11位——预留。
数位10——该位是类型位,它表明了这是一个接收缓存描述符还是传输缓存描述符。对于是接收缓存描述符的情况,驱动程序将把该位设置为0。
数位9到8——预留。
数位7——该位是一个流控制封包位,它表明接收到的封包是一个流控制封包。
数位6——该位是一个成帧故障位,它表示在接受到的封包中有一个成帧故障。
数位5——该位是一个接收器溢出位,它表示微代码在其溢出之前,不能够从硬件接收FIFO中移除数据。这表示或者是微代码没有足够快到能够将进程继续下去,或者是系统的空闲接收缓存描述符用尽了。
数位4——该位是一个CRC(循环冗余码)错误位,它表示该封包已经被接收到,但CRC不正确。
数位3——该位是短封包位,它表示一个接收到的封包小于64字节。
数位2——该位是长封包位,它表示一个接收到的封包长度大于最大值。
数位1——该位是多点传送位,它表示被接收到封包被作为一个硬件层多点传送
数位0——该位是广播位,它表示被接收到封包被作为一个硬件层广播。
控制/状态字(ATM)
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
I | | | | |
T | | | | | | | | | | |
数位15——这是一个中断位,其中对该位的设定将会导致在用数据填充该缓存描述符,并将其放置于rxbd队列中之后,微处理机发送一个中断给核心。
数位14到11——预留。
数位10——这是一个类型位,它表明了这是一个接收缓存描述符还是传输缓存描述符。对于是接收缓存描述符的情况,驱动程序将把该位设置为0。
数位9-0——预留。
为了接收缓存描述符,端口号区域将被微代码设定,以表明封包由哪个接口接收。
端口号
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
- |
IX |
类型 |
预留 |
MAC号 |
单元号 |
数位15——预留。
数位14——这是一个IX位,它表示该端口位于IX总线上。对于以太网和ATM而言,这一位都将被微代码设定为1。
数位13到10——是类型位区域,它表示了接口的类型:1——以太网;2——ATM;而3-15——预留。
数位9到6——预留。
数位5到3——这些位表示端口的MAC号。
数位2到0——这些位表示端口的单元号。
数据长度区域在被放入rxfree队列中之前被初始化为0。在微处理机将缓存描述符插入rxbd队列之前,它们将对数据长度区域进行设定,令其反映被拷贝到缓存区中的字节总数。这包括数据连接报头和有效负载。在ATM的情况下,只有在第一单元上的ATM报头被拷贝,而同一封包后面的ATM报头被丢弃。数据大小区域表示微处理机可以拷贝到与该缓存描述符所关联的缓冲区中去的最大数据字节数。对以太网和ATM而言,它必须足够大从而包括一个完整的帧。这意味着它对于ATM而言至少是1552,对于以太网而言至少是1514。
数据位置区域包括一个指针,指向与该缓存描述符所关联的缓冲区的起始点,该缓冲区包含了实际传输/接收的数据。必须在一个8字节的范围内接收这个缓存描述符。ATM微代码同样需要在该位置之前有8个字节,可用于存储临时数据。
用户数据区域可以被用于存储驱动程序所需的任意数据。这个区域从不会被微处理机查看或修改。例如,如果数据位置指针指向一个大的数据结构内部,这个区域可以被用于很容易的找到所包含的数据结构。
下面描述了传输缓存描述符,同样也是上面所述的一般形式。当核心希望传输一个封包时,驱动程序从txfree队列中移出一个缓存描述符,填充所有需要的传输区域,并将它插入到txbd队列上。核心驱动程序不需要等待封包被发送,而取而代之的是能够立即使用下一个传输缓存描述符。这将会继续下去,直至核心处理器运行完所有要发送的封包,或者txfree队列为空。一旦核心处理器插入了封包,它就不允许更改在传输缓存描述符中的任何区域。在每一个封包都已经被发送之后,如果需要,微处理机将缓存描述符插入txdone队列并中断核心程序。之后,驱动程序从这个队列中移除缓存描述符,释放任何相关的系统内存,并将缓存描述符放回到txfree队列中。
下面描述了传输缓存描述符的格式。
下一个缓存描述符区域用于生成一个描述符链,通过识别被处理链中的下一缓存描述符,该描述符链被核心处理。
控制/状态字包含的信息被用于识别与中断和类型相关的某些信息。
控制/状态字(以太网)
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
I | | | | |
T | | | | | | | | | | |
数位15——这是中断位,当其被设定时,它会在将数据传输和将缓存描述符放置于txdone队列上之后,使微处理机发送一个中断给核心程序。
数位14到11——预留。
数位10——该位是类型位,它表明了这是一个接收缓存描述符还是传输缓存描述符。对于是接收缓存描述符的情况,驱动程序将把该位设置为0。
数位9到0——预留。
控制/状态字(ATM)
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
I | | | | |
T | | | | | | | | | | |
数位15——这是中断位,当其被设定时,它会在将数据传输和将缓存描述符放置于txdone队列上之后,使微处理机发送一个中断给核心程序。
数位14到11——预留。
数位10——该位是类型位,它表明了这是一个接收缓存描述符还是传输缓存描述符。对于是接收缓存描述符的情况,驱动程序将把该位设置为0。
数位9到0——预留。
端口号被用来表示封包将在哪一个端口被发送。
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
- |
IX |
类型 |
预留 |
MAC号 |
单元号 |
数位15——预留。
数位14——这是一个IX位,它表示该端口位于IX总线上。对于以太网和ATM而言,这一位都将被设定为1。
数位13到10——这是类型位区域,它表示了接口的类型:1——以太网;2——ATM;而3-15——预留。
数位9到6——预留。
数位5到3——这些位表示端口的MAC号。
数位2到0——这些位表示端口的单元号。
数据长度区域表示在缓存区内的数据字节数,该缓存区与要被传输的这个描述符相关联。
数据大小区域没有被传输缓存描述符使用,并将被初始化为零。
数据位置区域指向一个包含有要被发送的封包的缓存区的起始处。该封包必须已经包含了以太网或ATM数据连接报头。在ATM的情况中,只有第一单元的报头被包括在内。在以太网中,在数据位置指针上没有排列约束。在ATM中数据位置必须是8字节排列的。
用户数据区域可以被用于存储驱动程序所需的任意数据。这个区域从不会被微处理机查看或修改。例如,如果数据位置指针指向一个大的数据结构内部,这个区域可以被用于很容易的找到所包含的数据结构。
下面描述了在初始化时提供给微处理机的CSR块的配置。用于以太网和ATM接口的CRS的C代码在附录A中列出。用于以太网和ATM的CRS被分成两个部分,并且包含了用于控制微处理机操作的可配置参数。第一个是一个一般共同部分,它被该类型的所有接口共享,而第二部分包含了端口特征信息。
共同以太网CSR部分包含了不同队列数据结构的一个单一拷贝,它被共享给所有以太网端口,在下面列出:
·rxfree_push——指向八个IXP推式队列中的一个的指针。当核心程序结束对一个接收到的缓存描述符的处理时,驱动程序将会把该指针返回给使用该推式队列的rxfree表。
·rxfree_pull——指向八个IXP推式队列中的一个的指针。当微处理机需要一个接收缓存描述符,它们可以从这里得到一个。这个参数必须和rxfree_push一样与相同的推/拉式队列建立关联。
·txfree_push——与rxfree_push类似。核心驱动程序将在对传输缓存描述符进行处理之后,将它们从txdone_pull队列中插入到这里。
·txfree_pull——与rxfree_pull类似。当核心驱动程序需要一个空闲的传输缓存描述符时,它能够从这个队列中得到一个。
·txdone_push——个指针指向一个IXP推式队列,它存储了传输缓存描述符。在微处理机结束一个传输缓存描述符的处理时,它将会被插入该队列。
·txdone_pull——核心驱动程序能够从这个IXP拉式队列中找回传输缓存描述符。这使驱动程序在将一个缓存描述符插入txfree_push队列中之前,可以释放于它相关的任意内存。
·rxbd_tail——个指针指向接收队列的末尾。微处理机将会从这里开始接收输入的封包。
·rxbd_head——个指针指向接收队列的开头。核心驱动程序将会从这里开始接收输入的封包。
·txbd_tail——个指针指向传输队列的末尾。核心驱动程序将会在这里插入所有的传输缓存描述符。
·txbd_Head——个指针指向传输队列的开头。微处理机将会从这里移除已经被传输的缓存描述符。
在共同以太网CSR部分中也包括由所有以太网端口使用的中断向量(向量)。核心驱动程序负责将进入的封包进行多路分解,如果需要的话。
共同以太网CSR部分也包括一个中断事件/掩码寄存器(i_event/i_mask)。该事件寄存器和掩码寄存器是物理上不同的寄存器,但是包含相同的数位区域定义。事件寄存器将表示是不同的中断中的哪一个正在等待。然而,仅仅只有在掩码寄存器中的等效数位被设定时,实际的核心程序中断才会出现。
|
31 |
30 |
29 |
28 |
27 |
26 |
25 |
24 |
23 |
22 |
21 |
20 |
19 |
18 |
17 |
16 |
区域 |
TXB | | | | | | | | | | | | | | | |
|
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
区域 | |
RXE |
RXF | | | | | | | | | | | | | |
数位31——这是传输缓存区中断位。在一个缓存区已经被传输,并且相关缓存描述符被放置在txdone队列之后,由微处理机生成该中断。
数位30到15——预留。
数位14——这是接收错误中断位。如果在一个封包的接收期间出现一个错误,接受错误中断被生成。该缓存描述符仍然被插入到rxbd队列中,而bd_status表示导致错误的原因。
数位13——这是接收帧中断位。在一个帧已经被成功的接收之后,它被放置于rxbd队列之中,并生成接收帧中断。
数位1到0——预留。
共同以太网CSR部分的最后一个组成包括微处理机命令寄存器(mccr),它被用于发送命令给微处理机。
|
31 |
30 |
29 |
28 |
27 |
26 |
25 |
24 |
23 |
22 |
21 |
20 |
19 |
18 |
17 |
16 |
区域 |
端口 |
|
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
区域 |
BF |
|
|
|
|
|
|
|
|
|
|
|
操作码 |
数位31到16——这些数位包含了端口位区域,它被用于指定该命令被用于哪一个以太网端口。数位16表示端口0,而数位31表示端口15。通过在该区域中设定不止一个数位,一个命令有可能被应用于多个端口。
数位15——这是占用标记位,表示微处理机当前正在执行一个命令。驱动程序在对适当的参数进行初始化之后设定这个数位,并在之后等待这个数位被清空,这表示该命令已经被结束了。
数位3到0——这是操作码区域,它指出了在指定的端口上要由微处理机执行什么命令。
·0000——开始传输和接收,有可能在一个端口上同时开始传输和接收。这个命令等价于在一个开始传输命令之后紧跟着一个开始接收命令。
·0001——开始接收
·0010——开始传输
·0011——停止接收
·0100——停止传输
下面描述了以太网的端口指定CSR部分。第一组成部分将每一个以太网端口的物理地址设置为一个48位802.3MAC层地址。
最后一个组成部分设置了传输和接收控制寄存器(trcr)。
|
31 |
30 |
29 |
28 |
27 |
26 |
25 |
24 |
23 |
22 |
21 |
20 |
19 |
18 |
17 |
16 |
区域 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
区域 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TE |
RE |
数位31到2——预留。
数位1——该位激活传输程序。
数位2——该位激活接收程序。
下面描述了用于ATM网络的CRS结构,它也被分成两个部分。第一部分是一个单一的共同部分,它被共享给该种类型的所有接口,而第二部分包含端口指定信息。
共同ATM CSR部分包含一个不同数据结构的单一拷贝,它被所有的ATM端口共享,它与前面所述的用于以太网端口的队列结构相同。
在共同ATM CSR中还包含有中断向量(向量),它被所有ATM端口使用。核心驱动程序负责将进入的封包进行多路分解,如果需要的话。
中断事件/掩码寄存器(i_event/i_mask)。该事件寄存器和掩码寄存器是物理上不同的寄存器,但是包含相同的数位区域定义。事件寄存器将表示是不同的中断中的哪一个正在等待。然而,仅仅只有在掩码寄存器中的等效数位被设定时,实际的核心程序中断才会出现。
|
31 |
30 |
29 |
28 |
27 |
26 |
25 |
24 |
23 |
22 |
21 |
20 |
19 |
18 |
17 |
16 |
区域 |
TXB | | | | | | | | | | | | | | | |
|
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
区域 | |
RXE |
RXF | | | | | | | | | | | | | |
数位31——这是传输缓存位。在一个缓存区已经被传输,并且相关的缓存描述符被放置到txdone队列中之后,由微处理机生成这个中断。
数位30到15——预留。
数位14——这是接收错误中断位。如果在一个封包的接收期间出现一个错误,接受错误中断被生成。该缓存描述符仍然被插入到rxbd队列中,而bd_status区域表示导致错误的原因。
数位13——这是接收帧中断位。在一个帧已经被成功的接收之后,它被放置于rxbd队列之中,并生成接收帧中断。
数位1到0——预留。
共同ATM CSR部分的最后组成部分包括微处理机命令寄存器(mccr),它被用于发送命令给微处理机。
|
31 |
30 |
29 |
28 |
27 |
26 |
25 |
24 |
23 |
22 |
21 |
20 |
19 |
18 |
17 |
16 |
区域 |
端口 |
|
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
区域 |
BF | | | | | | | | | | | |
操作码 |
数位31到16——这些数位包含了端口位区域,它被用于指定该命令被用于哪一个ATM端口。数位16表示端口0,而数位31表示端口15。通过在该区域中设定不止一个数位,一个命令有可能被应用于多个端口。
数位15——这是占用标记位,表示微处理机当前正在执行一个命令。驱动程序在对适当的参数进行初始化之后设定这个数位,并在之后等待这个数位被清空,这表示该命令已经被结束了。
数位3到0——这是操作码区域,它指出了在指定的端口上要由微处理机执行什么命令。
·0000——开始传输和接收,有可能在一个端口上同时开始传输和接收。这个命令等价于在一个开始传输命令之后紧跟着一个开始接收命令。
·0001——开始接收
·0010——开始传输
·0011——停止接收
·0100——停止传输
端口指定ATM CSR
下面描述了ATM的端口指定CSR部分,它包含一个对传输和接收控制寄存器(trcr)进行设置的数位区域。
|
31 |
30 |
29 |
28 |
27 |
26 |
25 |
24 |
23 |
22 |
21 |
20 |
19 |
18 |
17 |
16 |
区域 | | | | | | | | | | | | | | | | |
|
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
区域 | | | | | | | | | | | | | | |
TE |
RE |
数位31到2——预留。
数位1——该位激活传输程序。
数位0——该位激活接收程序。
下面的部分包含了在微处理机的初始化和重设中以及封包的传输和接收中所需的步骤的功能描述。
·初始化步骤:(1)禁止传输和接收;(2)设置CSR(速度的,双向通讯的,BD的,地址信息,等等);(3)清空事件寄存器;(4)设定掩码寄存器;(5)激活中断;并(6)开始传输和接收。
·传输步骤:(1)填写描述符;(2)放入传输队列;并(3)处理TX中断。
·接收步骤:(1)当一个封包到达一个接口时,微处理机从接收空闲串列中移除一个缓冲描述符,并开始用数据填充它,在封包的接收结束后,状态信息被更新,而该缓冲描述符被放置于rxbd队列中,如果需要的话,也生成一个核心程序的中断,如果核心驱动程序处理封包不够快以及微处理器用完了可用的接收描述符的话,将简单的停止处理所有进入的封包直至描述符变为可用;(2)存储来自于描述符的信息;(3)重设描述符的值;并(4)放置于rxfree队列中;
·重设步骤:(1)停止传输和接收;(2)更改设置参数;并(3)输入重设命令。
关于硬件的初始化,驱动程序负责某些以太网和ATM硬件的初始化。对以太网而言,尤其是Intell IXF440以太网,核心驱动程序负责在Intel IXF440多通道10/100Mbps以太网控制器上设置如下寄存器。
·ixf_pcr——端口控制寄存器
·ixf_fbr——FIFO总线模式寄存器
·ixf_rpr——接收参数寄存器
·ixf_smr——串行模式寄存器
·ixf_ftr——FIFO阈值寄存器
·ixf_rmfr——接收模式滤波寄存器
·ixf_ier——中断激活寄存器
附录A——数据结构
这个附录包含了上面所述的数据结构的’C’语言定义。
/*
**缓冲描述符
*/
typedef struct BufferDescriptor{
struct BufferDescriptor*bd_next;
u_int16bd_status;
u_int16bd_port;
u_int16bd_len1;
u_int16bd_len2;
u_int16bd_size1;
u_int16bd_size2;
u_int8*bd_data1;
u_int32bd_usr1;
u_int8*bd_data2;
u_int32bd_usr2;
}BD;
/*以太网接口*/
typedef struct{
/*以太网端口指定数据*/
u_int8paddr[6];/*单点传送地址*/
u_int8res1[2];/*边界填充*/
u_int32res2[2];/*预留*/
u_int32trcr;/*传输/接收控制寄存器*/
<dp n="d53"/>
}Enet_port;
typedef struct{
/*以太网共同数据*/
BD*free_push;/*用于空BD的IXP推式队列*/
BD*free_pull;/*用于空BD的IXP拉式队列*/
BD*txdone_push;/*用于被传输BD的IXP推式队列*/
BD*txdone_pull;/*用于被传输BD的IXP拉式队列*/
BD*rxbd_tail;/*接收队列尾部*/
BD*rxbd_head;/*接收队列头部*/
BD*txbd_tail;/*传输队列尾部*/
BD*txbd_head;/*传输队列头部*/
u_int32vector /*中断向量*/
u_int32i_event;/*中断事件寄存器*/
u_int32i_mask;/*中断掩码寄存器*/
u_int32mccr;/*微代码命令寄存器*/
}Enet_common;
/*ATM接口*/
typedef struct{
/*ATM端口指定信息*/
u_int32trcr;/*传输/控制寄存器*/
}ATM_port;
typedef struct{
<dp n="d54"/>
/*ATM共同数据*/
BD*free_push;/*用于空BD的IXP推式队列*/
BD*free_pull;/*用于空BD的IXP拉式队列*/
BD*txdone_push;/*用于被传输BD的IXP推式队列*/
BD*txdone_pull;/*用于被传输BD的IXP拉式队列*/
BD*rxbd_tail;/*接收队列尾部*/
BD*rxbd_head;/*接收队列头部*/
BD*txbd_tail;/*传输队列尾部*/
BD*txbd_head;/*传输队列头部*/
u_int32vector /*中断向量*/
u_int32i_event;/*中断事件寄存器*/
u_int32i_mask;/*中断掩码寄存器*/
u_int32mccr;/*微代码命令寄存器*/
}ATM_common;
/*
**IXP1200共享内存映射
*/
typedef struct{
Enet_common enet_common;
Enet_port enet_port[MAX_ENET_PORTS];
ATM_common atm_common;
ATM_port atm_port[MAX_ATM_PORTS];
}IXP1200MM;
前面的描述和附图包含了本发明的说明性实施例。前面所叙述的实施例和方法会因本领域技术人员的能力,经验和偏好的不同而不同。所列出的方法步骤遵循一定的顺序,并不构成对本方法步骤的顺序的限定。前述的描述和附图只不过是本发明的解释和说明,本发明并未以此为限定,而是在权利要求中对范围做出了限定。拥有本公开资料的本领域技术人员,无需从本发明范围出发就能够作出修改和变化。