日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 路由指向策略,Linux 路由 学习笔记 之六 策略规则的添加

發(fā)布時(shí)間:2024/4/19 linux 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 路由指向策略,Linux 路由 学习笔记 之六 策略规则的添加 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上一節(jié)分析了策略規(guī)則相關(guān)的數(shù)據(jù)結(jié)構(gòu),本節(jié)就分析一下策略規(guī)則的添加。對于策略規(guī)則的功能模塊,由于 v4 、 v6 都有用到,所以該模塊也和鄰居模塊一樣,抽象出了通用規(guī)則的接口函數(shù),然后根據(jù)傳入的參數(shù)來進(jìn)入?yún)f(xié)議相關(guān)的策略規(guī)則的接口函數(shù),即分為通用接口

上一節(jié)分析了策略規(guī)則相關(guān)的數(shù)據(jù)結(jié)構(gòu),本節(jié)就分析一下策略規(guī)則的添加。對于策略規(guī)則的功能模塊,由于v4、v6都有用到,所以該模塊也和鄰居模塊一樣,抽象出了通用規(guī)則的接口函數(shù),然后根據(jù)傳入的參數(shù)來進(jìn)入?yún)f(xié)議相關(guān)的策略規(guī)則的接口函數(shù),即分為通用接口函數(shù)與協(xié)議相關(guān)的接口函數(shù)。

1.通用規(guī)則的添加及處理流程

應(yīng)用層主要是通過netlink模塊實(shí)現(xiàn)與內(nèi)核中策略規(guī)則模塊通信,從而實(shí)現(xiàn)策略規(guī)則的添加、刪除等操作(本文不關(guān)注netlink接口實(shí)現(xiàn),僅介紹策略規(guī)則功能模塊相關(guān)的接口)。

1.1?fib_nl_newrule

不管是v4還是v6,在內(nèi)核中添加一個(gè)規(guī)則,首先就會調(diào)用通用接口函數(shù)fib_nl_newrule,然后由該函數(shù)找到協(xié)議相關(guān)的接口函數(shù),再調(diào)用協(xié)議相關(guān)的接口函數(shù),實(shí)現(xiàn)策略規(guī)則的添加。

下面我們就分析一下這個(gè)函數(shù),這個(gè)函數(shù)主要執(zhí)行一下功能:

1.根據(jù)應(yīng)用層傳遞的協(xié)議類型,查找到相應(yīng)注冊的struct?fib_rules_ops類型的變量

對于ipv4而言,就是fib4_rules_ops

2.??對應(yīng)用層傳遞的值進(jìn)行解析,并對傳入的源或者目的地址值進(jìn)行合理性檢查

3.創(chuàng)建一個(gè)新的fib?rule緩存,并對優(yōu)先級、接口index、接口名稱、fwmark、action、table_id進(jìn)行設(shè)置

4.調(diào)用協(xié)議對應(yīng)的configure函數(shù),對fib?rule的源、目的ip、tos等值進(jìn)行配置

5.增加此fib?rule的引用計(jì)數(shù),并根據(jù)優(yōu)先級將新的fib?rule插入到協(xié)議相關(guān)的rules_list鏈表對應(yīng)的位置

int?fib_nl_newrule(struct?sk_buff?*skb,?struct?nlmsghdr*?nlh,?void?*arg)

{

struct?fib_rule_hdr?*frh?=?nlmsg_data(nlh);

struct?fib_rules_ops?*ops?=?NULL;

struct?fib_rule?*rule,?*r,?*last?=?NULL;

struct?nlattr?*tb[FRA_MAX+1];

int?err?=?-EINVAL;

if?(nlh->nlmsg_len?

goto?errout;

/*對于ipv4而言,獲取到的值即為fib4_rules_ops*/

ops?=?lookup_rules_ops(frh->family);

if?(ops?==?NULL)?{

err?=?EAFNOSUPPORT;

goto?errout;

}

/*對應(yīng)用層傳遞的參數(shù)進(jìn)行解析,并存放在tb中*/

err?=?nlmsg_parse(nlh,?sizeof(*frh),?tb,?FRA_MAX,?ops->policy);

if?(err?

goto?errout;

/*調(diào)用validate_rulemsg對傳入的源或者目的地址值進(jìn)行合理性檢查*/

err?=?validate_rulemsg(frh,?tb,?ops);

if?(err?

goto?errout;

/*

創(chuàng)建一個(gè)struct?fib_rule?*類型的變量

*/

rule?=?kzalloc(ops->rule_size,?GFP_KERNEL);

if?(rule?==?NULL)?{

err?=?-ENOMEM;

goto?errout;

}

/*

根據(jù)應(yīng)用層傳遞的參數(shù),對優(yōu)先級進(jìn)行設(shè)置

*/

if?(tb[FRA_PRIORITY])

rule->pref?=?nla_get_u32(tb[FRA_PRIORITY]);

/*

根據(jù)應(yīng)用層傳遞的參數(shù),決定是否需要設(shè)置fib?rule的ifindex值

*/

if?(tb[FRA_IFNAME])?{

struct?net_device?*dev;

rule->ifindex?=?-1;

nla_strlcpy(rule->ifname,?tb[FRA_IFNAME],?IFNAMSIZ);

dev?=?__dev_get_by_name(rule->ifname);

if?(dev)

rule->ifindex?=?dev->ifindex;

}

/*

設(shè)置fib?rule的fwmark,實(shí)際應(yīng)用中可以根據(jù)這個(gè)值決定路由表的選擇,即實(shí)現(xiàn)

策略路由的功能

*/

if?(tb[FRA_FWMARK])?{

rule->mark?=?nla_get_u32(tb[FRA_FWMARK]);

if?(rule->mark)

/*?compatibility:?if?the?mark?value?is?non-zero?all?bits

*?are?compared?unless?a?mask?is?explicitly?specified.

*/

rule->mark_mask?=?0xFFFFFFFF;

}

/*

設(shè)置fwmark的掩碼值

*/

if?(tb[FRA_FWMASK])

rule->mark_mask?=?nla_get_u32(tb[FRA_FWMASK]);

/*設(shè)置規(guī)則的action以及與該規(guī)則關(guān)聯(lián)的路由表id,實(shí)現(xiàn)規(guī)則與路由表的關(guān)聯(lián)*/

rule->action?=?frh->action;

rule->flags?=?frh->flags;

rule->table?=?frh_get_table(frh,?tb);

/*

當(dāng)沒有為策略規(guī)則配置優(yōu)先級也沒有默認(rèn)優(yōu)先級時(shí),則會調(diào)用該協(xié)議對應(yīng)

的default_pref獲取一個(gè)默認(rèn)的優(yōu)先級.

對于ipv4,其default_pref的原理是獲取規(guī)則鏈表中非0優(yōu)先級中的最高優(yōu)先級,

即獲取的默認(rèn)優(yōu)先級是除0優(yōu)先級的規(guī)則外,最高的優(yōu)先級。

*/

if?(!rule->pref?&&?ops->default_pref)

rule->pref?=?ops->default_pref();

/*

調(diào)用該協(xié)議對應(yīng)的configure,該該策略進(jìn)行配置

*/

err?=?ops->configure(rule,?skb,?nlh,?frh,?tb);

if?(err?

goto?errout_free;

/*

遍歷規(guī)則鏈表,找到第一個(gè)pref值比當(dāng)前剛創(chuàng)建的fib?rule的pref值大的fib?rule:

若找到符合要求的規(guī)則,則將新創(chuàng)建的策略規(guī)則添加到符合要求的規(guī)則

之前;

若在搜索完整個(gè)鏈表仍沒有找到符合要求的規(guī)則,則將該規(guī)則添加到

當(dāng)前鏈表已有規(guī)則的租后,即鏈尾。

*/

list_for_each_entry(r,?ops->rules_list,?list)?{

if?(r->pref?>?rule->pref)

break;

last?=?r;

}

fib_rule_get(rule);

if?(last)

list_add_rcu(&rule->list,?&last->list);

else

list_add_rcu(&rule->list,?ops->rules_list);

notify_rule_change(RTM_NEWRULE,?rule,?ops,?nlh,?NETLINK_CB(skb).pid);

rules_ops_put(ops);

return?0;

errout_free:

kfree(rule);

errout:

rules_ops_put(ops);

return?err;

}

1.2?lookup_rules_ops

在上面的函數(shù)中,在根據(jù)協(xié)議簇查找相應(yīng)的已注冊的協(xié)議相關(guān)的fib_rules_ops變量時(shí),調(diào)用了函數(shù)lookup_rules_ops來實(shí)現(xiàn)的,下面就分析一下這個(gè)函數(shù)

功能:根據(jù)協(xié)議簇在鏈表rules_ops中查找符合要求的struct?fib_rules_ops類型的

變量對于ipv4而言,即為fib4_rules_ops

static?struct?fib_rules_ops?*lookup_rules_ops(int?family)

{

struct?fib_rules_ops?*ops;

rcu_read_lock();

list_for_each_entry_rcu(ops,?&rules_ops,?list)?{

if?(ops->family?==?family)?{

if?(!try_module_get(ops->owner))

ops?=?NULL;

rcu_read_unlock();

return?ops;

}

}

rcu_read_unlock();

return?NULL;

}

接著就調(diào)用函數(shù)validate_rulemsg,對于應(yīng)用層傳遞的參數(shù)進(jìn)行了合法性檢查,下面就分析一下這個(gè)函數(shù)

1.3?validate_rulemsg

這個(gè)函數(shù)主要判斷frh與tb中的源、目的地址相關(guān)的參數(shù)是否合法,下面分析下這個(gè)函數(shù)的執(zhí)行流程:

1.若源地址的長度不為0時(shí),若tb[FRA_SRC]中為空,或者傳入的地址

長度與相應(yīng)協(xié)議規(guī)定的地址長度不等,或者實(shí)際傳遞的地址的

實(shí)際長度與相應(yīng)協(xié)議規(guī)定的地址長度不等時(shí),則返回-EINVAL。

1.若目的地址的長度不為0時(shí),若tb[FRA_SRC]中為空,或者傳入的地址

長度與相應(yīng)協(xié)議規(guī)定的地址長度不等,或者實(shí)際傳遞的地址的

實(shí)際長度與相應(yīng)協(xié)議規(guī)定的地址長度不等時(shí),則返回-EINVAL。

static?int?validate_rulemsg(struct?fib_rule_hdr?*frh,?struct?nlattr?**tb,

struct?fib_rules_ops?*ops)

{

int?err?=?-EINVAL;

if?(frh->src_len)

if?(tb[FRA_SRC]?==?NULL?||

frh->src_len?>?(ops->addr_size?*?8)?||

nla_len(tb[FRA_SRC])?!=?ops->addr_size)

goto?errout;

if?(frh->dst_len)

if?(tb[FRA_DST]?==?NULL?||

frh->dst_len?>?(ops->addr_size?*?8)?||

nla_len(tb[FRA_DST])?!=?ops->addr_size)

goto?errout;

err?=?0;

errout:

return?err;

}

接著就是調(diào)用協(xié)議相關(guān)的函數(shù),進(jìn)行協(xié)議相關(guān)的配置操作了,下面我們就分析之

2.協(xié)議相關(guān)的添加處理流程

本節(jié)以ipv4為例,在函數(shù)fib_nl_newrule中,通過ops->configure函數(shù)調(diào)用了協(xié)議相關(guān)的配置函數(shù),而對于ipv4而言,即是函數(shù)fib4_rule_configure。下面就分析一下這個(gè)函數(shù)。

2.1??fib4_rule_configure

當(dāng)新增加一個(gè)ipv4的fib?rule規(guī)則時(shí),就會調(diào)用該函數(shù),對

新創(chuàng)建的struct?fib4_rule類型的變量進(jìn)行初始化操作,即根據(jù)

應(yīng)用層傳遞的配置參數(shù),設(shè)置struct?fib4_rule類型的變量的

源ip地址、源ip的掩碼值、目的ip地址、目的ip的掩碼值、

路由表id、tos等

static?int?fib4_rule_configure(struct?fib_rule?*rule,?struct?sk_buff?*skb,

struct?nlmsghdr?*nlh,?struct?fib_rule_hdr?*frh,

struct?nlattr?**tb)

{

int?err?=?-EINVAL;

struct?fib4_rule?*rule4?=?(struct?fib4_rule?*)?rule;

if?(frh->tos?&?~IPTOS_TOS_MASK)

goto?errout;

if?(rule->table?==?RT_TABLE_UNSPEC)?{

if?(rule->action?==?FR_ACT_TO_TBL)?{

struct?fib_table?*table;

/*

若應(yīng)用層沒有設(shè)置路由表的id,則調(diào)用fib_empty_table創(chuàng)建

一個(gè)新的路由表,并將新創(chuàng)建的路由表的id傳遞

給rule->table

(使用如下命令,即會使系統(tǒng)創(chuàng)建一個(gè)新的路由表

#?ip?rule?add?from?192.168.192.1?table?0)

*/

table?=?fib_empty_table();

if?(table?==?NULL)?{

err?=?-ENOBUFS;

goto?errout;

}

rule->table?=?table->tb_id;

}

}

if?(frh->src_len)

rule4->src?=?nla_get_be32(tb[FRA_SRC]);

if?(frh->dst_len)

rule4->dst?=?nla_get_be32(tb[FRA_DST]);

#ifdef?CONFIG_NET_CLS_ROUTE

if?(tb[FRA_FLOW])

rule4->tclassid?=?nla_get_u32(tb[FRA_FLOW]);

#endif

rule4->src_len?=?frh->src_len;

rule4->srcmask?=?inet_make_mask(rule4->src_len);

rule4->dst_len?=?frh->dst_len;

rule4->dstmask?=?inet_make_mask(rule4->dst_len);

rule4->tos?=?frh->tos;

err?=?0;

errout:

return?err;

}

剛才的函數(shù)里,有調(diào)用函數(shù)fib_empty_table,那我們就分析一下這個(gè)函數(shù)。

2.2?fib_empty_table

功能:從0開始到RT_TABLE_MAX為止,找到第一個(gè)沒有創(chuàng)建路由表的id后,

即調(diào)用fib_new_table創(chuàng)建此id對應(yīng)的路由表,并返回路由表的首地址;

若從0開始到RT_TABLE_MAX的id,都有創(chuàng)建相應(yīng)的路由表了,則程序

返回NULL

static?struct?fib_table?*fib_empty_table(void)

{

u32?id;

for?(id?=?1;?id?<=?RT_TABLE_MAX;?id++)

if?(fib_get_table(id)?==?NULL)

return?fib_new_table(id);

return?NULL;

}

以上就是策略規(guī)則添加的整個(gè)分析流程,通過分析這個(gè)流程,發(fā)現(xiàn)在添加策略規(guī)則時(shí),函數(shù)并沒有判斷要添加的規(guī)則是否已存在,這樣會不會導(dǎo)致策略規(guī)則的重復(fù)添加呢?還是在應(yīng)用層進(jìn)行的判斷呢?我感覺應(yīng)該是應(yīng)用層做了判斷,由于目前一直在學(xué)習(xí)kernel里的代碼,應(yīng)用層的代碼目前是沒有時(shí)間分析了。

總結(jié)

以上是生活随笔為你收集整理的linux 路由指向策略,Linux 路由 学习笔记 之六 策略规则的添加的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。