从现在开始学习路由相关的代码,在分析代码之前, 我们还是先分析数据结构,把数据结构之间的关系理解了以后,再理解代码就相对轻松多了。本小节先分析路由相关的数据结构。内核里面大多模块定义的数据结构之间一般都是使用链表或者hash表实现连接操作。
对于路由表,相关的数据结构有fib_table、fn_hash、fn_zone、fib_node、fib_alias、fib_info、fib_nh等, 下面分别介绍这几个数据结构
路由表结构,该结构为一个路由表的抽象,包括路由表的id、路由添加函数、路由查找函数、路由删除函数等
struct fib_table {
/*使用hash链表将多个路由表变量链接在一起*/
struct hlist_node tb_hlist;
/*表id*/
u32 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 *, struct fib_config *);
/*路由项删除函数*/
int (*tb_delete)(struct fib_table *, struct fib_config *);
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);
/*可变长数组,主要是用来指向掩码相关的hash数组*/
unsigned char tb_data[0];
};
该结构主要用于描述以掩码划分的区域结构以及掩码区域之间的关系
对于ipv4来说,掩码可以为0-32共33种可能,因此对于一个fn_hash来说,则
定义了一个包含33个fn_zone的数组,而链表fn_zone_list,主要是将一个路由表里的
fn_zone链接在一起(以掩码大小的顺序排列,主要是在路由查找时,先匹配最长掩码对应的路由,以提高路由匹配的精确度)。
struct fn_hash {
struct fn_zone *fn_zones[33];
struct fn_zone *fn_zone_list;
};
以掩码划分的区域结构抽象,将掩码长度相同的所有路由放在同一个fn_zone中hash表中。
struct fn_zone {
/*指向下一个非空的fn_zone*/
struct fn_zone *fz_next;
/*指向路由项关联的hash链表,对于掩码相关的目的ip地址,根据目的网络地址
的hash值,将新的fn_node节点插入到相应的hash链表中*/
struct hlist_head *fz_hash; /* Hash table pointer */
/*fn_node结构变量的个数,fn_node并不能说是对一个路由项的抽象,可以看成对一个
目的网络地址的抽象,而对于相同的目的网络地址,可以根据tos、priority、mark值创建
不同的路由,所以一个fn_node结构中fn_alias才能算作是对一个路由项的抽象*/
int fz_nent; /* Number of entries */
/*该fn_zone中fz_hash链表的个数*/
int fz_divisor; /* Hash divisor */
/*fz_hash的mask值*/
u32 fz_hashmask; /* (fz_divisor - 1) */
#define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
/*以上两个值用于fz_hash数组的容量扩充相关*/
/*该fn_zone对应的掩码长度*/
int fz_order; /* Zone order */
/*根据fz_order而得到的掩码值*/
__be32 fz_mask;
/*获取该fn_zone对应的掩码值*/
#define FZ_MASK(fz) ((fz)->fz_mask)
};
抽象为一个目的网络地址相同的所有路由项的基础结构,其中的fn_alias,表示该结构所包含的已存在的路由项的链表,fn_key为该结构对应的目的网络地址值,
用于和掩码长度相同的其他fib_node区分,对于同一个fn_zone里的fib_node,都链接到fn_zone->fz_hash中相应的hash表中
struct fib_node {
/*用于将hash值相同,且目的网络地址值不同,且网络掩
码相同的fib_node变量链接在一起*/
struct hlist_node fn_hash;
struct list_head fn_alias;
__be32 fn_key;
};
该结构可以理解为一个路由项的抽象。
当路由项的目的网络地址相同时,可以根据这个结构变量区分不同的路由项。包括tos、type、scope、state以及fib_info来区分一个路由项
方法:
1.首先根据tos、type、scope等确定一个fib_alias
2.当fib_alias确定以后,再根据priority等值确定一个fib_info,
3.根据fib_info确定出口设备与下一跳网关的ip地址。
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_scope表示路由的scope,取值范围如下:
RT_SCOPE_UNIVERSE:该选项用于所有通向非直连目的地的路由表项,即
应用层创建的路由中包含via的路由
RT_SCOPE_LINK:该选项用于目的地址为本地网络的路由项
RT_SCOPE_HOST:该选项用于路由为本机接口,
RT_SCOPE_NOWHERE:该选项用于路由不可到达
enum rt_scope_t
{
RT_SCOPE_UNIVERSE=0,
/* User defined values */
RT_SCOPE_SITE=200,
RT_SCOPE_LINK=253,
RT_SCOPE_HOST=254,
RT_SCOPE_NOWHERE=255
};
功能:主要是用来获取出口设备以及下一跳网关的数据结构,以及路由项的优先级,路由创建协议fib_protocol(RTPROTO_KERNEL、RTPROTO_BOOT、RTPROTO_STATIC等取值)。而fib_hash与fib_lhash则是将fib_info链接到对应的hash链表fib_info_hash[]与fib_info_laddrhash[]中去的。
struct fib_info {
/*这两个指针用于将该fib_info链接到hash链表中*/
struct hlist_node fib_hash;
struct hlist_node fib_lhash;
int fib_treeref;
atomic_t fib_clntref;
/*标识是否将要释放该fib_info变量*/
int fib_dead;
unsigned fib_flags;
int fib_protocol;
__be32 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]
/*fib_nh变量的个数*/
int fib_nhs;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
int fib_power;
#endif
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
u32 fib_mp_alg;
#endif
/*可变长度数组,用于动态申请fib_nh内存空间*/
struct fib_nh fib_nh[0];
#define fib_dev fib_nh[0].nh_dev
};
包含下一跳网关及出口设备的结构
struct fib_nh {
/*数据包输出设备接口*/
struct net_device *nh_dev;
/*将fib_nh变量链接在hash链表中*/
struct hlist_node nh_hash;
/*包含该变量的fib_info变量*/
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
/*出口设备的index*/
int nh_oif;
/*下一跳网关地址*/
__be32 nh_gw;
};
而nh_hash是用来将fib_nh变量链接到对应的fib_info_devhash[]链表中的。
以上就是相应的数据结构分析,下面是这些数据结构之间的逻辑关系。没有给出fib_info_hash[]、fib_info_laddrhash[]与fib_info之间的,也没有给出fib_nh与fib_info_devhash之间的关系
以上就是路由相关的数据结构,下一节开始分析路由的添加与删除等功能。以上分析的数据结构没有包含路由缓存相关的数据结构,等到介绍到路由缓存时再进行分析。