linux網路通訊協定棧分析筆記12-路由2-FIB1

來源:互聯網
上載者:User
上一章我們看到了通過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.cstatic 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相關的初始化來看,冒出了相當多的資料結構,看都看暈了,我們下面就從處理操作等角度來看看這些結構是如何使用,並達到什麼樣的路由操作目的

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.