1、 路由表相关的数据结构
struct fib_table {
struct hlist_node tb_hlist;
u32 tb_id;//路由表id(0-255)
unsigned tb_stamp;
int tb_default;//()
int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res);
//路由查找函数,会被初始化为fn_hash_lookup
int (*tb_insert)(struct fib_table *, struct fib_config *);
//路由插入函数,会被初始化为fn_hash_insert
int (*tb_delete)(struct fib_table *, struct fib_config *);
//路由删除函数,会被初始化为fn_hash_delete
int (*tb_dump)(struct fib_table *table, struct sk_buff *skb,
struct netlink_callback *cb);
int (*tb_flush)(struct fib_table *table);
//路由flush函数,会被初始化为fn_hash_flush,将设置为RTNH_F_DEAD的fib_info结构的内存释放掉
void (*tb_select_default)(struct fib_table *table,
const struct flowi *flp, struct fib_result *res);
unsigned char tb_data[0];
};
struct fn_hash {
struct fn_zone *fn_zones[33];//以网络掩码区分不同的子网,此处每一个fn_zone,代表网络掩码相同的子网
struct fn_zone *fn_zone_list;//fn_zone的链表头存储在该结构体中
};
struct fn_zone {
struct fn_zone *fz_next; /* Next not empty zone */
struct hlist_head *fz_hash; /* Hash table pointer */
int fz_nent; /* Number of entries */
int fz_divisor; /* Hash divisor */
u32 fz_hashmask; /* (fz_divisor - 1) */
#define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
int fz_order; /* Zone order */
__be32 fz_mask;
#define FZ_MASK(fz) ((fz)->fz_mask)
};
struct fib_node {
struct hlist_node fn_hash;
struct list_head fn_alias;
__be32 fn_key;
struct fib_alias fn_embedded_alias;
};
struct fib_alias {
struct list_head fa_list;
struct fib_info *fa_info;
u8 fa_tos;
u8 fa_type;
u8 fa_scope;
u8 fa_state;
#ifdef CONFIG_IP_FIB_TRIE
struct rcu_head rcu;
#endif
};
/*
* This structure contains data shared by many of routes.
*/
struct fib_info {
struct hlist_node fib_hash; //用于链接fib_info,这样可以通过fib_find_info来实现快速查找fib_info
struct hlist_node fib_lhash;
struct net *fib_net;
int fib_treeref;
atomic_t fib_clntref;
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]
int fib_nhs;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
int fib_power;
#endif
struct fib_nh fib_nh[0];
#define fib_dev fib_nh[0].nh_dev
};
下一跳路由相关的结构体
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;
__be32 nh_gw;
};
这些数据结构之间的关联如下(深入理解linux网络 一书中的图):
a) 在一个路由表中,是根据网络掩码来进行划分不同的网域,因此在一个路由表中,会有33个fn_zone;
b) 在网络掩码相同的网域中,根据子网值来进行进一步的划分(如192.168.1/24则,fn_key为192.168.1)每一个子网对应于一个fib_node
c) 对于每一个特定子网,更进一步的划分依据是tos值、priority、scope等,,这对应于结构体fib_alias,fib_alias相关的链表以ip_tos的升序排列
d) 而fib_info就代表一条路由基本信息,在同一个fib_alias中,fib_info相关的链表以fib_priority的升序排列。
关于hash值的生成,是调用函数fn_hash生成的(将一个fn_zone中所有的fib_node根据生成的hash值,链接到不同的fn_zone-> fz_hash[]中)。
static inline u32 fn_hash(__be32 key, struct fn_zone *fz)
{
u32 h = ntohl(key)>>(32 - fz->fz_order);
h ^= (h>>20);
h ^= (h>>10);
h ^= (h>>5);
h &= FZ_HASHMASK(fz);
return h;
}
只要理解了上面的几个数据结构直接的关系,就能够很好的理解路由添加、删除等操作了(无非就是将路由信息添加到该数据表中)。
路由表的初始化
路由的添加:
ip route add 192.168.1.0/24 dev eth0 src 192.168.1.111
在函数ip_fib_init,会通过调用函数rtnl_register,将inet_rtm_newroute、inet_rtm_delroute
注册到到rtnl_msg_handlers[PF_INET][ RTM_NEWROUTE]. doit、
rtnl_msg_handlers[PF_INET][ RTM_DELROUTE]. doit中
这样当应用层通过rtnetlink向kernel层发送类型为RTM_NEWROUTE、RTM_DELROUTE的消息时,内核就会调用函数rtnetlink_rcv_msg找到正确的rtnl_msg_handlers[].doit,接着就会调用到函数inet_rtm_newroute、inet_rtm_delroute执行添加路由与删除路由的操作。