|
FIB(fowarding information base)转发信息库
通过display fib命令显示信息为
Flag:
U:Usable G:Gateway H:Host B:Blackhole D:Dynamic S:Static
R:Reject E:Equal cost multi-path L:Generated by ARP or ESIS
Destination/Mask Nexthop Flag TimeStamp Interface
10.153.17.0/24 10.153.17.99 U t[0] Vlan-interface1
10.153.18.88/32 127.0.0.1 GHU t[0] InLoopBack0
10.153.18.0/24 10.153.18.88 U t[0] LoopBack0
10.153.17.99/32 127.0.0.1 GHU t[0] InLoopBack0
127.0.0.0/8 127.0.0.1 U t[0] InLoopBack0
fib表中各个字段分别为:
Destination/Mask :目的地址和掩码
Nexthop :下一跳地址,该地址是与路由器直连的地址。
Flag :对该条转发信息性质描述
TimeStamp :时间戳(这个不知道代表什么意思)?FIB项生成的时间。它不用于转发,但在分布式系统中可作为故障诊断与排错
时的参考信息,可以验证FIB项是否从主控板到I/O板定时刷新,同时还可以用于内部老化功能。
Interface :转发的出接口
各个flag所代表的意思如下表:
表2-1 display fib命令显示信息表
字段 |
描述 |
Destination/Mask |
目的地址/掩码长度 |
Nexthop |
转发的下一跳地址 |
Flag |
标志: "U"——代表是路由UP,可用 "G"——代表是网关路由 "H"——代表是本机路由 "B"——代表是黑洞路由 "D"——代表是动态路由 "S"——代表是静态路由 "R"——代表是被拒绝的路由,不可用 “E”——代表是多路径等价路由 "L"——代表是由ARP或ESIS生成的路由 |
TimeStamp |
时间戳 |
Interface |
转发接口 |
路由器转发分组的关键是FIB表,在系统中报文转发时查找的是FIB表而非路由表。这是因为路由表表示所有的有效路由所形成的表现,并不指导转发,FIB表是网络层用来控制数据报发送的。
路由器转发分组的关键是FIB表,在系统中报文转发时查找的是FIB表而非路由表。这是因为路由表表示所有的有效路由所形成的表项,并不指导转发。FIB表是网络层用来控制数据报发送的。FIB中包含了路由器在转发报文时所必需的一组最小信息。
参考FIB详解:从数据结构方面来理解FIB表
宏CONFIG_IP_MULTIPLE_TABLES表示路由策略,当定义了该宏,也即意味着内核配置了“路由策略”。产生的最大的不同就是内核可以使用多达256张FIB。其实,这256张FIB在内核中的表示是一个全局数组:
struct fib_table *myfib_tables[RT_TABLE_MAX+1];
而宏RT_TABLE_MAX定义如下:
enum rt_class_t
{
RT_TABLE_UNSPEC=0,
RT_TABLE_DEFAULT=253,
RT_TABLE_MAIN=254,
RT_TABLE_LOCAL=255,
__RT_TABLE_MAX
};
#define RT_TABLE_MAX (__RT_TABLE_MAX - 1)
我们可以看到,虽然这张表多达256项,但枚举类型rt_class_t给出的表示最常用的也就三项,在系统初始化时,由内核配置生成的路由表只有RT_TABLE_MAIN,RT_TABLE_LOCAL两张。
main表中存放的是路由类型为RTN_UNICAST的所有路由项,即网关或直接连接的路由。在myfib_add_ifaddr函数中是这样添加
main表项的:对于某个网络设备接口的一个IP地址,如果目的地址的网络号不是零网络(网络号与子网号全为零),并且它是primary地址,同时,它
不是D类地址(网络号与子网号占32位)。最后一个条件是:它不是一个环回地址(device上有flag
IFF_LOOPBACK)。那么,就添加为main表项,如果是环回地址,则添加为local表的一个表项。
在我们的系统中,有两个已开启的网络设备接口eth0和lo,eth0上配置的primary
IP地址是172.16.48.2,所以,相应的,main表中就只有一项。为main表添加路由项的时候,该路由项的目的地址是子网内的所有主机(把主
机号部分字节清零),而对应于lo,在local表中也有一项,其类型为RTN_LOCAL(注:前一篇文章中的local表的hash
8中的路由项表述有误,类型应该是RTN_LOCAL,而不是RTN_BORADCAST)。
而其它的路由项全部归入local表,主要是广播路由项和本地路由项。在我们的系统环境下,local表共有7项,每个网络设备接口占三项。分别是本地地
址(源跟目的地址一致),子网广播地址(主机号全为1),子网广播地址(主机号为零)。再加上一个lo的RTN_LOCAL项。
现在我们再来看myfib_add_ifaddr函数的路由添加策略。对于一个传入的ip地址(结构struct
in_ifaddr表示),如果它是secondary地址,首先要确保同一个网络设备接口上存在一个跟其同类型的primary地址(网络号与子网号完
全一致),因为,路由项的信息中的源地址全是primary的,secondary地址其实没有实际使用,它不会在路由表中产生路由项。然后,向
local表添加一项目的地址是它本身的,类型为RTN_LOCAL的路由项;如果该ip地址结构中存在广播地址,并且不是受限广播地址
(255.255.255.255),那么向local表添加一个广播路由项;然后,对符合加入main表的条件进行判断,如果符合,除了加入main
表,最后,如果不是D类地址,还要加入两个广播地址(其实,已经跟前面有重叠,很多情况下不会实际触发加入的动作,只要记住,一个ip地址项对应最多有两
个广播地址就可以了)。
下面我们来看FIB的数据结构。一张FIB在内核中被表示为一个对象struct
fib_table,之所以说它是一个对象,而不是一个结构,是因为它不仅仅是一组数据集合,它还包含了定义在该对象之上的方法,包括表项的插入,查找,
删除,刷新等等。下面是其定义:
struct fib_table {
unsigned char tb_id;
unsigned tb_stamp;
int (*tb_lookup)(struct fib_table *tb,
const struct flowi *flp, struct fib_result *res);
int (*tb_insert)(struct fib_table *table, struct rtmsg *r,
struct kern_rta *rta, struct nlmsghdr *n,
struct netlink_skb_parms *req);
int (*tb_delete)(struct fib_table *table, struct rtmsg *r,
struct kern_rta *rta, struct nlmsghdr *n,
struct netlink_skb_parms *req);
int (*tb_dump)(struct fib_table *table, struct sk_buff *skb,
struct netlink_callback *cb);
int (*tb_flush)(struct fib_table *table);
void (*tb_select_default)(struct fib_table *table,
const struct flowi *flp, struct fib_result *res);
unsigned char tb_data[0];
};
这些成员函数我们在分析代码时都会提供其完整的实现,现在重点关注其数据成员。tb_id表明该表的用途(RT_TABLE_LOCAL,
RT_TABLE_MAIN等),同时也表明它在全局数组myfib_tables中的位置(RT_TABLE_LOCAL==255,
RT_TABLE_MAIN==254)。tb_data是一个很重要的数据成员,它包含了所在FIB的全部路由信息,可能会有点令人费>,因为它
的类型仅仅是一个unsigned char的数组而已,甚至更奇怪的是,它的长度是零,也就是说,根本不存在。看了下面的代码就可以明了:
struct fib_table *tb = kmalloc( sizeof(struct fib_table)
+ sizeof(struct fn_hash), GFP_KERNEL );
memset( tb->tb_data, 0, sizeof(struct fn_hash) );
所以,tb_data实际上是一个指向结构struct fn_hash的指针。下面是结构struct fn_hash的定义:
struct fn_hash{
struct fn_zone *fn_zones[33];
struct fn_zone *fn_zone_list;
};
在解释struct fn_hash之前,先看一下strut fn_zone:
struct fn_zone{
struct fn_zone *fz_next;
struct hlist_head *fz_hash;
int fz_nent;
int fz_divisor;
u32 fz_hashmask;
int fz_order;
u32 fz_mask;
};
这是一个区域,所有目的地址长度相同的路由项划入同一个区域,以链表的形式组织在fz_hash成员中,同时,fz_order记录目的地址长度,
fz_mask为目的地址掩码(比如:fz_order为24,则fz_mask为ffffff)。比如,在我们的系统配置环境中,两个网络设备接口有共
七个路由项。其中的6项,其目的地址长度为6,归入同一个zone中,放在fz_hash成员中。成员fz_nent表明该zone中的路由项的数量,为
6。fz_hash其实是一个哈项数组,共有fz_divisor项(初始为16),fz_hashmask为数组的掩码(初始为f)。路由项以目的IP
地址为主键,定位到数组的某一项。
对于ipv4来讲,目的地址不会超过32位,所以fz_order的取值范围是0-32。所以,struct
fn_hash中fn_zones被定义为一个具有33项的数组,对应33个区域。在我们的配置系统中,fn_zones[32]和fn_zones
[8]被用到了。同时,fn_zone_list把fn_zones中的已创建出来的zone按fz_order从大到小的顺序组织成一个链表。这些做法
都是出于效率的考虑。
所以,fn_hash是一个组织路由域的数据结构,同一个域里的fn_zone通过fz_next组织成一个链表。
同一个域中,所有的路由项组织在哈希表fz_hash中,一个路由项由结构struct fib_node表示。下面是该结构的定义:
struct fib_node {
struct hlist_node fn_hash;
struct list_head fn_alias;
u32 fn_key;
};
fn_hash用于在zone中组织链表,关于内核的一些基本数据结构,我们将专门进行分析,这里不再赘述。fn_key即目的地址IP,
fn_alias指向一个结构体struct fib_alias的链表,下面是结构struct fib_alias的定义:
struct fib_alias {
struct list_head fa_list;
struct rcu_head rcu;
struct fib_info *fa_info;
u8 fa_tos;
u8 fa_type;
u8 fa_scope;
u8 fa_state;
};
fa_tos表示服务类型,一般为0,即一般服务;fa_type的值在我们的系统中为RTN_LOCAL,
RTN_UNICAST和RTN_BORADCAST。fa_scope其实表示的是到目的地址的距离,对本地接收来说,就是
RT_SCOPE_HOST,对子网内广播和子网内其它地址来说,就是RT_SCOPE_LINK。fa_state只有在本地接收时,为
FA_S_ACCESSED,其它暂无定义。
fa_info作为struct fib_alias的成员,含有更为详细的路由项信息。下面是其定义:
struct fib_info {
struct hlist_node fib_hash;
struct hlist_node fib_lhash;
int fib_treeref;
atomic_t fib_clntref;
int fib_dead;
unsigned fib_flags;
int fib_protocol;
u32 fib_prefsrc;
u32 fib_priority;
u32 fib_metrics[RTAX_MAX];
#define fib_mtu fib_metrics[RTAX_MTU-1]
#define fib_window fib_metrics[RTAX_WINDOW-1]
#define fib_rtt fib_metrics[RTAX_RTT-1]
#define fib_advmss fib_metrics[RTAX_ADVMSS-1]
int fib_nhs;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
int fib_power;
#endif
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
u32 fib_mp_alg;
#endif
struct fib_nh fib_nh[0];
#define fib_dev fib_nh[0].nh_dev
};
fib_treeref表示本路由信息项在struct
fib_table结构的整个树型结构中被引用的次数,而fib_clntref是另一个引用计数。fib_dead表示本项当前是否是活的。
fib_protocol表示该路由信息是通过什么途径建立起来的,其可能有取值有:
#define RTPROT_UNSPEC 0
#define RTPROT_REDIRECT 1 //该路由是由ICMP重定义安装的。
#define RTPROT_KERNEL 2 //该路由是由内核安装的。
#define RTPROT_BOOT 3 3 //该路由是在系统启动时安装的。
#define RTPROT_STATIC 4 //该路由是由管理员安装的。
除此之外,还有一些取值,不过是用于用户态的,我们当前在模块初始化过程中安装的路由都是RTPROT_KERNEL的。fib_prefsrc是我们的
local地址。最后,fib_nh是一个结构struct
fib_nh的的数组,数组的大小由fib_nhs决定。该结构表示路由中的下一跳,下面是其定义:
struct fib_nh {
struct net_device *nh_dev;
struct hlist_node nh_hash;
struct fib_info *nh_parent;
unsigned nh_flags;
unsigned char nh_scope;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
int nh_weight;
int nh_power;
#endif
#ifdef CONFIG_NET_CLS_ROUTE
__u32 nh_tclassid;
#endif
int nh_oif;
u32 nh_gw;
};
1. 我想知道三层交换的交换过程。交换机接收到PCA发送过来的一个数据包,发现含有三层IP信息,于是发送给自己的路由模块,端口指向三层模块的端口,MAC地址也是三层模块的MAC地址。这是第一步,有错吗?
-----------------------------------
这一步没有错。只是一点要注意,其实交换机只有1个MAC地址,不管是三层模块还是什么都只有一个MAC。可能你在查接口的时候发现每个接口都有对应的MAC,但是那个只是用来区分端口的。实际机身MAC只有一个。
===============================================================
2.经过查看FIB表,不是已经知道了,要从哪个接口发出数据,发到什么MAC吗?
FIB表记录的主要是记录路由信息,在FIB表获取到下一跳地址,然后去邻接表是查找下一跳地址对应的MAC,进行rewrite
MAC地址,实现转发。这个过程其实很快的。也可以理解成FIB和ADJ表是同时运作。如果不理解你可以想想EIGRP的拓扑表和邻居表,OSPF的
Database和邻居表,也是这样的运作原理。
原则一IPv6离散性 | 原则二不同掩码长度 | 原则三Prefix嵌套和分支 | Search Tree视角 | 建楼房视角 | 点评 | |
用例A+1递增路由 | 不满足 | 满足 | 不满足 | 多果椰子树 | 联排 | 性能和容量测试不准确 |
用例B随机路由 | 满足 | 满足 | 不满足 | 单果椰子树 | 别墅 | 容量较好,性能测试不准确 |
NE80E通过命令display ip routing-table verbose能看到NextHop、RelyNextHop,他们的区别是什么?display ip routing-table verbose命令显示如下:
Destination: 0.0.0.0/0
Protocol: BGP Process ID: 0
Preference: 100 Cost: 0
NextHop: 202.97.32.243 Interface: Pos2/0/0
RelyNextHop: 222.83.17.5 Neighbour: 202.97.32.243
Tunnel ID: 0x0 Label: NULL
State: Active Adv Derived Age: 00h44m09s
Tag: 0
其中NextHop表示路由表项的下一跳,RelyNextHop表示fib表实际转发的下一跳!
首先路由表和FIB是不同实体,作用也不一样。路由是上层协议来用的,Display ip routing显示的是协议添加路由时设置的下一跳,在路由表中称之为原始下一跳,这个下一跳不一定直接可达。而FIB是用于指导转发的,它的下一跳必须是直接可达。路由管理模块通过对路由的原始下一跳进行迭代找到这个直接下一跳,并将其设置到FIB当中来指导转发。
1.RIB与FIB的区别:
RIB:路由表
FIB:转发信息表
FIB 表更多是出现在需要快速转发的路由器上,这种路由器上的路由表条目通常都达成千上万条,如果按照传统的检索路由表进行转发的方式,其转发效率很低,FIB 表作为路由表的一种精简形式出现,通常只记录常用的表项。当需要选路时,先检索FIB表,如果找不到再检索路由表。
在大部分路由器中,RIB表现为路由表的形式, FIB则表现为高速缓存的形式,此在内容上是路由表的一个子集,是依靠路由表来生成的。
一般来说,FIB是进行高速查找而组织的数据结构(不是简单的把路由表中的内容复制出来,数据存储和检索方式等都不同于路由表的组成像是)。
RIB 就一个字:全,知道到所有的地方怎么走,但是速度慢。
FIB就一个字:快,只知道常走的路怎么走,速度快。
如果是分布式设备,通常FIB分布在LPU上,由LPU上的cpu实现快速选路,如果在LPU找不到路,才上到MPU处理,这里的RIB保存了最全的路由信息,可以提供不常用的选路结果。
2.ARP表和FDB表的区别:
ARP表:IP和MAC的对应关系;
FDB表:MAC+VLAN和PORT的对应关系;
两个最大的区别在于ARP是三层转发,FDB是用于二层转发。也就是说,就算两个设备不在一个网段或者压根没配IP,只要两者之间的链路层是连通的,就可以通过FDB表进行数据的转发!
FDB表的最主要的作用就是在于交换机二层选路,试想,如果仅仅有ARP表,没有FDB表,就好像只知道地名和方位,而不知道经过哪条路才能到达目的地,设备是无法正常工作的。FDB表的作用就在于告诉设备从某个端口出去就可以到某个目的MAC。
那么FDB表是怎么形成的呢?很简单,交换机会在收到数据帧时,提取数据帧中的源MAC、VLAN和接收数据帧的端口等组成FDB表的条目。当下次有到该VLAN中的该MAC的报文就直接从该端口丢出去就OK了。
当然,FDB表和ARP表一样,都有一个老化时间。
标题:TCAM表和FIB表有什么关系? 作者:yeelone 时间:2010-12-12 19:52 | |
[font=宋体,]我想问个问题,我一直对CAM表和TCAM表不太理解,CAM表是二层
的,TCAM表是三层,平常我们在二层交换机上不是查找ARP表吗?在三层交换机上不是查找FIB表吗?现在又说是查找TCAM表?所以,我想问的
是,CAM和ARP表有什么关系?TCAM表和FIB表有什么关系? 关于TCAM,是不是交换机计算出了FIB表后,就用FIB的条目去填充TCAM内存表,然后TCAM还会加入一些ACL和QOS的控制信息。 不知道这样理解对不对? 我就是有一点很不清楚,以前看书时是说,三层交换机是查找FIB表和ARP表来进行转发。学到后面又说是查找TCAM表。我就不明白两者之间是什么关系?要如何应用?[/font] |
|
标题: 作者:独钩寒江雪 时间:2010-12-12 22:43 | |
二层交换中catalyst交换机使用CAM(内容可描述内存)表,当帧到达交换机端口,交换机主动学习源MAC地址并
记录在CAM表中,同时记录了到达的端口号、VLAN和时间戳。如果在一个端口学习到的MAC地址到达了另一个端口,前一条CAM表中的记录会被删掉,新
增一条最近的记录。如果CAM表中已记录的MAC地址到达原来相同的端口,仅仅修改CAM表记录的时间戳。 交换机通常拥有很大的CAM表以便在帧转发时用来查询,然而,在大的网络上没有足够的空间来容纳所有可能的地址,为合理管理CAM表的空间,过时的条目会在一段时间后失效,默认情况下,如在300秒内没有相同源MAC的帧到达,CAM表中的条目会被删除。 当主机的MAC地址在交换机的端口被学习到,而后主机移动到另一个交换机端口去了,当新端口得知了这个地址,主机原先对应的CAM表条目会在300秒后超时失效,但为避免有重复的CAM条目,交换机会肃清先前的一个条目。因为MAC地址的唯一性,这是一种安全的猜测。 在传统的路由中,ACL能匹配、过滤或控制特定的数据流,ACL是由一或多个存取控制条目(ACE)或匹配语句组成的,根据ACL来检查可能占用额外的时间,增加转发数据包的延迟。 然而在多层交换机中,所有的ACL的匹配过程是通过硬件实现的,TCAM允许根据整个控制列表在一次简单的表查询中检查数据包,多数交换机都有多个的TCAM表以便可以同时根据多个ACL检查数据包,甚至允许二层和三层的转发决策完全并行地进行。 TCAM是CAM表概念的一种扩展,在CAM表中使用索引(或称为关键值、通常是MAC地址)查找结果值(通常是端口号或VLAN号),TCAM同样使用 表查找操作,但被改进并可以完成更复杂的操作。TCAM条目由VALUE、MASK、RESULT(VMR)组成,帧或数据包头部的内容被放到TCAM 表,在TCAM表中根据值和掩码的组合来匹配产生结果。 CAM表 存贮着与VLAN相结合的物理端口上的有效的MAC地址 FIB表 是在MPLS中解释说的基于CEF所产生的路由表 T CAM表 主要用于快速查找ACL、路由等表项。它是从CAM的基础上发展而来的。 A R P表 实现通过IP地址得知其物理地址 |