linux网络协议栈分析笔记12-路由2-FIB1

来源:互联网 发布:html5仿淘宝手机商城 编辑:程序博客网 时间:2024/05/29 04:00
上一章我们看到了通过fib_lookup去查找了路由信息,这一章我们就看看fib到底是什么
FIB(Forward Information Base) 转发信息库

inet_init()->ip_init()->ip_rt_init()->

ipv4_dst_ops.kmem_cachep =
          kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0,         rtable结构高速缓存的创建
                      SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);

rt_hash_table = (struct rt_hash_bucket *)                                              路由缓存的hash表创建
          alloc_large_system_hash("IP route cache",
                         sizeof(struct rt_hash_bucket),
                         rhash_entries,
                         (totalram_pages >= 128 * 1024) ?
                         15 : 17,
                         0,
                         &rt_hash_log,
                         &rt_hash_mask,
                         rhash_entries ? 0 : 512 * 1024);
     memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket));

ip_fib_init()->
     注册与路由相关的rtnetlink 消息以及他的处理函数,主要处理路由添加删除  
rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL);
          rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL);
          rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib); 

register_pernet_subsys(&fib_net_ops);    注册协议栈子系统,也就是路由系统。 重点--fib_net_ops
          register_netdevice_notifier(&fib_netdev_notifier);         通知链注册
          register_inetaddr_notifier(&fib_inetaddr_notifier);
          fib_hash_init()

fib_hash_init()    该函数出现在fib_hash.c   fib_trie.c两个文件中都有,系统可配置两种路由表组织算法,默认hash算法

void __init fib_hash_init(void)
{
     fn_hash_kmem = kmem_cache_create("ip_fib_hash", sizeof(struct fib_node),     fib_node高速缓存创建
                         0, SLAB_PANIC, NULL);

     fn_alias_kmem = kmem_cache_create("ip_fib_alias", sizeof(struct fib_alias),      fib_alias高速缓存创建
                           0, SLAB_PANIC, NULL);

}
主要数据结构:
struct fib_node {        代表一个路由指向的子网
     struct hlist_node     fn_hash;                    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;                   TOS
     u8               fa_type;                 路由类型
     u8               fa_scope;               路由范围
     u8               fa_state;                状态标志
#ifdef CONFIG_IP_FIB_TRIE
     struct rcu_head          rcu;
#endif
};


fib_net_ops:
static struct pernet_operations fib_net_ops = {
     .init = fib_net_init,
     .exit = fib_net_exit,
};

fib_net_init()
{
 ip_fib_net_init(net);

 nl_fib_lookup_init(net);                  netlink初始化相关

 fib_proc_init(net);                          初始化proc文件系统
}

static int __net_init ip_fib_net_init(struct net *net)
{
     int err;
     unsigned int i;

     net->ipv4.fib_table_hash = kzalloc(
               sizeof(struct hlist_head)*FIB_TABLE_HASHSZ, GFP_KERNEL);          申请256大小的hash表
     if (net->ipv4.fib_table_hash == NULL)
          return -ENOMEM;

     for (i = 0; i < FIB_TABLE_HASHSZ; i++)
          INIT_HLIST_HEAD(&net->ipv4.fib_table_hash[i]);      初始化每个hash表的冲突链

     err = fib4_rules_init(net);   
  有了256个表,就得提一提Linux的查找路由表的规则, 也就是策略路由ip rule add/del ...
     if (err < 0)
          goto fail;
     return 0;

fail:
     kfree(net->ipv4.fib_table_hash);
     return err;
}  

fib4_rules_init()     有两个,如果打开多路由表的宏时,CONFIG_IP_MULTIPLE_TABLES  我们看fib_rules.c中的   
int __net_init fib4_rules_init(struct net *net)
{
     int err;
     struct fib_rules_ops *ops;
给ops分配空间,并以fib4_rules_ops_template初始化ops
     ops = kmemdup(&fib4_rules_ops_template, sizeof(*ops), GFP_KERNEL);
     if (ops == NULL)
          return -ENOMEM;
     INIT_LIST_HEAD(&ops->rules_list);
     ops->fro_net = net;

     fib_rules_register(ops);              把协议族不同的路由表规则链起来  通过list串到net的rules_ops
                                                     list_add_tail_rcu(&ops->list, &net->rules_ops);

     err = fib_default_rules_init(ops);
     if (err < 0)
          goto fail;
     net->ipv4.rules_ops = ops;
     return 0;

fail:
     /* also cleans all rules already added */
     fib_rules_unregister(ops);
     kfree(ops);
     return err;
}

static struct fib_rules_ops fib4_rules_ops_template = {
     .family          = AF_INET,                                   协议族
     .rule_size     = sizeof(struct fib4_rule),
     .addr_size     = sizeof(u32),
     .action          = fib4_rule_action,
     .match          = fib4_rule_match,
     .configure     = fib4_rule_configure,
     .compare     = fib4_rule_compare,
     .fill          = fib4_rule_fill,
     .default_pref     = fib4_rule_default_pref,
     .nlmsg_payload     = fib4_rule_nlmsg_payload,
     .flush_cache     = fib4_rule_flush_cache,
     .nlgroup     = RTNLGRP_IPV4_RULE,
     .policy          = fib4_rule_policy,
     .owner          = THIS_MODULE,
};

fib_default_rules_init()          创建三个最基本的路由表local,main,default的规则表
static int fib_default_rules_init(struct fib_rules_ops *ops)
{
     int err;

     err = fib_default_rule_add(ops, 0, RT_TABLE_LOCAL, FIB_RULE_PERMANENT);
     if (err < 0)
          return err;
     err = fib_default_rule_add(ops, 0x7FFE, RT_TABLE_MAIN, 0);
     if (err < 0)
          return err;
     err = fib_default_rule_add(ops, 0x7FFF, RT_TABLE_DEFAULT, 0);
     if (err < 0)
          return err;
     return 0;
}

int fib_default_rule_add(struct fib_rules_ops *ops,u32 pref, u32 table, u32 flags)
{
     struct fib_rule *r;

     r = kzalloc(ops->rule_size, GFP_KERNEL);             申请fib rule结构
     if (r == NULL)
          return -ENOMEM;

     atomic_set(&r->refcnt, 1);
     r->action = FR_ACT_TO_TBL;
     r->pref = pref;
     r->table = table;
     r->flags = flags;
     r->fr_net = hold_net(ops->fro_net);

     /* The lock is not required here, the list in unreacheable
     * at the moment this function is called */
     list_add_tail(&r->list, &ops->rules_list);              加入fib_rules_ops的rules_list中
     return 0;
}

主要数据结构                               路由规则函数表的结构定义
struct fib_rules_ops
{
     int               family;                         协议栈
     struct list_head     list;                       链入net的net->rules_ops链中
     int               rule_size;                      规则结构长度
     int               addr_size;                     地址长度
     int               unresolved_rules;           
     int               nr_goto_rules;

     int               (*action)(struct fib_rule *,                    动作函数指针
                           struct flowi *, int,
                           struct fib_lookup_arg *);
     int               (*match)(struct fib_rule *,                    匹配函数指针
                         struct flowi *, int);
     int               (*configure)(struct fib_rule *,                配置函数指针
                              struct sk_buff *,
                              struct fib_rule_hdr *,
                              struct nlattr **);
     int               (*compare)(struct fib_rule *,                 比较函数指针
                            struct fib_rule_hdr *,
                            struct nlattr **);
     int               (*fill)(struct fib_rule *, struct sk_buff *,                    填写函数指针
                         struct fib_rule_hdr *);
     u32               (*default_pref)(struct fib_rules_ops *ops);                查找优先级函数指针
     size_t               (*nlmsg_payload)(struct fib_rule *);                     统计负载数据能力函数指针

     /* Called after modifications to the rules set, must flush
     * the route cache if one exists. */
     void               (*flush_cache)(struct fib_rules_ops *ops);   修改规则队列后,必须刷新缓存的函数指针

     int               nlgroup;
     const struct nla_policy     *policy;
     struct list_head     rules_list;             针对各个路由表的规则链表
     struct module          *owner;
     struct net          *fro_net;                 net与ops之间的关系
};



struct fib_rule
{
     struct list_head     list;                  
     atomic_t          refcnt;                      引用计数
     int               ifindex;                         网络设备id
     char               ifname[IFNAMSIZ];     用于保存网络设备名
     u32               mark;                         用于过滤作用
     u32               mark_mask;                掩码
     u32               pref;                           优先级
     u32               flags;                          标志位
     u32               table;                          路由函数表id
     u8               action;                          动作标识
     u32               target;  
     struct fib_rule *     ctarget;               当前规则
     struct rcu_head          rcu;
     struct net *          fr_net;                  net结构指针
};

上述几个结构的关系

如果没有打开CONFIG_IP_MULTIPLE_TABLES宏时,我们看fib_frontend.c
static int __net_init fib4_rules_init(struct net *net)
{
     struct fib_table *local_table, *main_table;

     local_table = fib_hash_table(RT_TABLE_LOCAL);   创建本地路由函数表
          return -ENOMEM;

     main_table  = fib_hash_table(RT_TABLE_MAIN);    创建主路由函数表
     if (main_table == NULL)
          goto fail;

     hlist_add_head_rcu(&local_table->tb_hlist,                                插入统一管理队列中
                    &net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX]);      
                                                            这里就是ip_fib_net_init中申请的那个256大小的hash表
     hlist_add_head_rcu(&main_table->tb_hlist,
                    &net->ipv4.fib_table_hash[TABLE_MAIN_INDEX]);
     return 0;

fail:
     kfree(local_table);
     return -ENOMEM;
}

struct fib_table *fib_hash_table(u32 id)
{
     struct fib_table *tb;

     tb = kmalloc(sizeof(struct fib_table) + sizeof(struct fn_hash),   这里又冒出了个两个新fib相关的结构
               GFP_KERNEL);
     if (tb == NULL)
          return NULL;

     tb->tb_id = id;
     tb->tb_default = -1;
     tb->tb_lookup = fn_hash_lookup;
     tb->tb_insert = fn_hash_insert;
     tb->tb_delete = fn_hash_delete;
     tb->tb_flush = fn_hash_flush;
     tb->tb_select_default = fn_hash_select_default;
     tb->tb_dump = fn_hash_dump;

     memset(tb->tb_data, 0, sizeof(struct fn_hash));
     return tb;
}

主要数据结构
struct fib_table {                                fib_table给路由表提供了查询路由信息的方法
     struct hlist_node tb_hlist;               hash节点
     u32          tb_id;                           标示符
     int          tb_default;            
     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);

     unsigned char     tb_data[0];
};

struct fn_hash {             路由区队列结构定义
     struct fn_zone     *fn_zones[33];             路由区队列
     struct fn_zone     *fn_zone_list;        指向第一个路由区表
};



struct fn_zone {           路由区结构定义
     struct fn_zone          *fz_next;     /* Next not empty zone     */             指向下一个非空路由区结构
     struct hlist_head     *fz_hash;     /* Hash table pointer     */                  hash队列
     int               fz_nent;     /* Number of entries     */                              包含的路由项个数

     int               fz_divisor;     /* Hash divisor          */                               hash头数量
     u32               fz_hashmask;     /* (fz_divisor - 1)     */                         hash头的掩码
#define FZ_HASHMASK(fz)          ((fz)->fz_hashmask)

     int               fz_order;     /* Zone order          */                                   子网掩码位数
     __be32               fz_mask;                                                                  子网掩码
#define FZ_MASK(fz)          ((fz)->fz_mask)
};

从fib相关的初始化来看,冒出了相当多的数据结构,看都看晕了,
我们下面就从处理操作等角度来看看这些结构是如何使用,并达到什么样的路由操作目的
原创粉丝点击