linux網路協議棧分析筆記14-路由4-FIB3
阿新 • • 發佈:2019-01-09
看完fib的查詢,弄清了一些資料結構的組織,我們再來看看路由表是如何建立的
從ip_fib_init註冊的兩個通知鏈來看,在IP地址傳送變動時會觸發通知鏈的處理函式,都會呼叫fib_add_ifaddr()來新增地址到路由中
這個裡面由呼叫了fib_magic來進行路由地址的操作。
static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa)
{
struct net *net = dev_net(ifa->ifa_dev->dev);
struct fib_table *tb;
struct fib_config cfg = { 路由配置結構
.fc_protocol = RTPROT_KERNEL,
.fc_type = type,
.fc_dst = dst,
.fc_dst_len = dst_len,
.fc_prefsrc = ifa->ifa_local,
.fc_oif = ifa->ifa_dev->dev->ifindex,
.fc_nlflags = NLM_F_CREATE | NLM_F_APPEND,
.fc_nlinfo = {
.nl_net = net,
},
};
if (type == RTN_UNICAST)
tb = fib_new_table(net, RT_TABLE_MAIN);
else
tb = fib_new_table(net, RT_TABLE_LOCAL);
if (tb == NULL)
return;
cfg.fc_table = tb->tb_id;
if (type != RTN_LOCAL)
cfg.fc_scope = RT_SCOPE_LINK;
else
cfg.fc_scope = RT_SCOPE_HOST;
if (cmd == RTM_NEWROUTE) 如果是新增命令 則插入
tb->tb_insert(tb, &cfg); fn_hash_insert;
else
tb->tb_delete(tb, &cfg); 否則,進行刪除
} fib_new_table() 先看CONFIG_IP_MULTIPLE_TABLES開啟的時候 struct fib_table *fib_new_table(struct net *net, u32 id)
{
struct fib_table *tb;
unsigned int h;
if (id == 0)
id = RT_TABLE_MAIN;
tb =fib_get_table(net, id); 通過id查詢路由表函式
if (tb)
return tb;
tb = fib_hash_table(id); 申請建立路由表
if (!tb)
return NULL;
h = id & (FIB_TABLE_HASHSZ - 1);
hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]);
return tb;
} struct fib_table *fib_get_table(struct net *net, u32 id)
{
struct fib_table *tb;
struct hlist_node *node;
struct hlist_head *head;
unsigned int h;
if (id == 0)
id = RT_TABLE_MAIN;
h = id & (FIB_TABLE_HASHSZ - 1);
rcu_read_lock();
head = &net->ipv4.fib_table_hash[h]; 得到衝突鏈頭
hlist_for_each_entry_rcu(tb, node, head, tb_hlist) { 匹配
if (tb->tb_id == id) {
rcu_read_unlock();
return tb;
}
}
rcu_read_unlock();
return NULL;
} 當然FIB的東西還有很多很多,資料結構關係錯綜複雜,鑑於時間和精力,無法再深入分析,這裡也只是弄清大概流程,拉通整個協議棧,等到有了系統的、全流程的觀念後,我們再來仔細深入分析具體的模組。 這裡有篇文章很好的闡述了linux kernel路由機制http://blog.csdn.net/bin323/article/details/642192 算是對上述的流程分析一個總結
{
struct net *net = dev_net(ifa->ifa_dev->dev);
struct fib_table *tb;
struct fib_config cfg
.fc_protocol = RTPROT_KERNEL,
.fc_type = type,
.fc_dst = dst,
.fc_dst_len = dst_len,
.fc_prefsrc = ifa->ifa_local,
.fc_oif = ifa->ifa_dev->dev->ifindex,
.fc_nlflags = NLM_F_CREATE | NLM_F_APPEND,
.fc_nlinfo = {
.nl_net = net,
},
};
if (type == RTN_UNICAST)
tb = fib_new_table(net, RT_TABLE_MAIN);
else
tb = fib_new_table(net, RT_TABLE_LOCAL);
if (tb == NULL)
return;
cfg.fc_table = tb->tb_id;
if (type != RTN_LOCAL)
cfg.fc_scope = RT_SCOPE_LINK;
else
cfg.fc_scope = RT_SCOPE_HOST;
if (cmd == RTM_NEWROUTE) 如果是新增命令 則插入
tb->tb_insert(tb, &cfg); fn_hash_insert;
else
tb->tb_delete(tb, &cfg); 否則,進行刪除
} fib_new_table() 先看CONFIG_IP_MULTIPLE_TABLES開啟的時候 struct fib_table *fib_new_table(struct net *net, u32 id)
{
struct fib_table *tb;
unsigned int h;
if (id == 0)
id = RT_TABLE_MAIN;
tb =fib_get_table(net, id); 通過id查詢路由表函式
if (tb)
return tb;
tb = fib_hash_table(id); 申請建立路由表
if (!tb)
return NULL;
h = id & (FIB_TABLE_HASHSZ - 1);
hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]);
return tb;
} struct fib_table *fib_get_table(struct net *net, u32 id)
{
struct fib_table *tb;
struct hlist_node *node;
struct hlist_head *head;
unsigned int h;
if (id == 0)
id = RT_TABLE_MAIN;
h = id & (FIB_TABLE_HASHSZ - 1);
rcu_read_lock();
head = &net->ipv4.fib_table_hash[h]; 得到衝突鏈頭
hlist_for_each_entry_rcu(tb, node, head, tb_hlist) { 匹配
if (tb->tb_id == id) {
rcu_read_unlock();
return tb;
}
}
rcu_read_unlock();
return NULL;
} 當然FIB的東西還有很多很多,資料結構關係錯綜複雜,鑑於時間和精力,無法再深入分析,這裡也只是弄清大概流程,拉通整個協議棧,等到有了系統的、全流程的觀念後,我們再來仔細深入分析具體的模組。 這裡有篇文章很好的闡述了linux kernel路由機制http://blog.csdn.net/bin323/article/details/642192 算是對上述的流程分析一個總結