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

上一章我们看到了通过 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相关的初始化来看,冒出了相当多的数据结构,看都看晕了,
我们下面就从处理操作等角度来看看这些结构是如何使用,并达到什么样的路由操作目的

你可能感兴趣的:(linux网络协议栈分析笔记12-路由2-FIB1)