linux内核等价多路径路由,Linux内核分析 - 网络[四]:路由表

路由表的创建

inet_init() -> ip_init() -> ip_fib_init() -> fib_net_init() -> ip_fib_net_init()[net\ipv4\fib_frontend.c]

首先为路由表分配空间,这里的每个表项hlist_head实际都会链接一个单独的路由表,FIB_TABLE_HASHSZ表示了分配多少个路由表,一般情况下至少有两个–LOCAL和MAIN。注意这里仅仅是表头的空间分配,还没有真正分配路由表空间。

net->ipv4.fib_table_hash = kzalloc(

sizeof(struct hlist_head)*FIB_TABLE_HASHSZ, GFP_KERNEL);

ip_fib_net_init() -> fib4_rules_init(),这里真正分配了路由表空间

local_table = fib_hash_table(RT_TABLE_LOCAL);

main_table= fib_hash_table(RT_TABLE_MAIN);

然后将local和main表链入之前的fib_table_hash中

hlist_add_head_rcu(&local_table->tb_hlist,

&net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX]);

hlist_add_head_rcu(&main_table->tb_hlist,

&net->ipv4.fib_table_hash[TABLE_MAIN_INDEX]);

最终生成结构如图,LOCAL表位于fib_table_hash[0],MAIN表位于fib_table_hash[1];两张表通过结构tb_hlist链入链表,而tb_id则标识了功能,255是LOCAL表,254是MAIN表。

关于这里的struct fn_hash,它表示了不同子网掩码长度的hash表[即fn_zone],对于ipv4,从0~32共33个。而fn_hash的实现则是fib_table的最后一个参数unsigned char tb_data[0]。

aca24e0bdf3462c737bb46c9b3e2eaf2.gif

注意到这里fn_zone还只是空指针,我们还只完成了路由表初始化的一部分。在启动阶段还会调用inet_rtm_newroute() -> fib_table_insert() -> fn_new_zone() [fib_hash.c]来创建fn_zone结构,前面已经讲过,fn_zone一共有33个,其中掩码长度为0[/0]表示为默认路由,fn_zone可以理解为相同掩码的地址集合。

首先为fn_zone分配空间

struct fn_zone *fz = kzalloc(sizeof(struct fn_zone), GFP_KERNEL);

传入参数z代表掩码长度,z = 0的掩码用于默认路由,一般只有一个,所以fz_divisor只需设为1;其它设为16;这里要提到fz_divisor的作用,fz->fz_hash并不是个单链表,而是一个哈希表,而哈希表的大小就是fz_divisor。

if (z) {

fz->fz_divisor = 16;

} else {

fz->fz_divisor = 1;

}

fz_hashmask实际是用于求余数的,当算出hash值,再hash & fz_hashmask就得出了在哈希表的位置;而fz_hash就是下一层的哈希表了,前面已经提过路由表被多组分层了,这里fz_hash就是根据fz_divisor大小来创建的;fz_order就是子网掩码长度;fz_mask就是子网掩码。

fz->fz_hashmask = (fz->fz_divisor - 1);

fz->fz_hash = fz_hash_alloc(fz->fz_divisor);

fz->fz_order = z;

fz->fz_mask = inet_make_mask(z);

从子网长度大于新添加fz的fn_zone中挑选一个不为空的fn_zones[i],将新创建的fz设成fn_zones[i].next;然后将fz根据掩码长度添加到fn_zones[]中相应位置;fn_zone_list始终指向掩码长度最长的fn_zone。

for (i=z+1; i<=32; i++)

if (table->fn_zones[i])

break;

if (i>32) {

fz->fz_next = table->fn_zone_list;

table->fn_zone_list = fz;

} else {

fz->fz_next = table->fn_zones[i]->fz_next;

table->fn_zones[i]->fz_next = fz;

}

table->fn_zones[z] = fz;

这里的fn_hash是数组与链表的结合体,看下fn_hash定义

struct fn_hash {

struct fn_zone*fn_zones[33];

struct fn_zone*fn_zone_list;

};

fn_hash包含33数组元素,每个元素存放一定掩码长度的fn_zone,其中fn_zone[i]存储掩码长度为i。而fn_zone通过内部属性fz_next又彼此串连起来,形成单向链表,其中fn_zone_list可以看作链表头,而这里链表的组织顺序是倒序的,即从掩码长到短。

89b9200259e4660652bbb153ddc6b47e.gif

到这里,fz_hash所分配的哈希表还没有插入内容,这部分为fib_insert_node()完成。

inet_rtm_newroute() -> fib_table_insert() -> fib_insert_node() [net\ipv4\fib_hash.c]

这里f是fib_node,可以理解为具有相同网络地址的路由项集合。根据fn_key(网络地址)和fz(掩码长度)来计算hash值,决定将f插入fz_hash的哪个项。

struct hlist_head *head = &fz->fz_hash[fn_hash(f->fn_key, fz)];

hlist_add_head(&f->fn_hash, head);

}

如何fib_node还不存在,则会创建它,这里的kmem_cache_zalloc()其实就是内存分配

new_f = kmem_cache_zalloc(fn_hash_kmem, GFP_KERNEL);

if (new_f == NULL)

goto out;

INIT_HLIST_NODE(&new_f->fn_hash);

INIT_LIST_HEAD(&new_f->fn_alias);

new_f->fn_key = key;

f = new_f;

路由表最后一层是fib_info,具体的路由信息都存储在此,它由fib_create_info()创建。

首先为fib_info分配空间,由于fib_info的最后一个属性是struct fib_nh fib_nh[0],因此大小是fib_info + nhs * fib_nh,这里的fib_nh代表了下一跳(next hop)的信息,nhs代表了下一跳的数目,一般情况下nhs=1,除非配置了支持多路径。

fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL);

设置fi的相关属性

fi->fib_net = hold_net(net);

fi->fib_protocol = cfg->fc_protocol;

fi->fib_flags = cfg->fc_flags;

fi->fib_priority = cfg->fc_priority;

fi->fib_prefsrc = cfg->fc_prefsrc;

fi->fib_nhs = nhs;

使fi后面所有的nh->nh_parent指向fi,设置后如图所示

change_nexthops(fi) {

nexthop_nh->nh_parent = fi;

} endfor_nexthops(fi)

f9a2046523812bbf75d0cff65f3e36f4.gif

设置fib_nh的属性,这里仅展示了单一路径的情况:

struct fib_nh *nh = fi->fib_nh;

nh->nh_oif = cfg->fc_oif;

nh->nh_gw = cfg->fc_gw;

nh->nh_flags = cfg->fc_flags;

然后,再根据cfg->fc_scope值来设置nh的其余属性。如果scope是RT_SCOPE_HOST,则设置下一跳scope为RT_SCOPE_NOWHERE

if (cfg->fc_scope == RT_SCOPE_HOST) {

struct fib_nh *nh = fi->fib_nh;

nh->nh_scope = RT_SCOPE_NOWHERE;

nh->nh_dev = dev_get_by_index(net, fi->fib_nh->nh_oif);

}

如果scope是RT_SCOPE_LINK或RT_SCOPE_UNIVERSE,则设置下跳

change_nexthops(fi) {

if ((err = fib_check_nh(cfg, fi, nexthop_nh)) != 0)

goto failure;

} endfor_nexthops(fi)

最后,将fi链入链表中,这里要注意的是所有的fib_info(只要创建了的)都会加入fib_info_hash中,如果路由项使用了优先地址属性,还会加入fib_info_laddrhash中。

hlist_add_head(&fi->fib_hash,

&fib_info_hash[fib_info_hashfn(fi)]);

if (fi->fib_prefsrc) {

struct hlist_head *head;

head = &fib_info_laddrhash[fib_laddr_hashfn(fi->fib_prefsrc)];

hlist_add_head(&fi->fib_lhash, head);

}0b1331709591d260c1c78e86d0c51c18.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/486148.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2017级面向对象程序设计 作业二

以下均以扫描方式为例&#xff0c;即电梯只会在最底层和最高层选择掉头&#xff0c;路途中遇到路径方向相同的乘客将他带上电梯。 文字描述面向过程实现的步骤&#xff1a; 一. 定义有关电梯的变量&#xff0c;如&#xff1a;1.电梯当前所在楼层.&#xff0c;2. 电梯内的人数&a…

新型支架状电极允许人类思想操作计算机

Illustration: Synchron来源&#xff1a;IEEE电气电子工程师据悉&#xff0c;两名患有神经肌肉疾病的澳大利亚人在他们的大脑中植入了支架状的电极&#xff0c;使他们能够利用自己的思想操作电脑&#xff0c;从而恢复了一些个人独立性。据发明者介绍&#xff0c;这是这种被称为…

java中的foreach

foreach 并不是java中的关键字&#xff0c;是for语句的特殊简化版&#xff0c;在比那里数组&#xff0c;集合时&#xff0c;foreach更加简单快捷&#xff0c;从字面上的意思理解 foreach 也就是 “ for每一个 ”的意思&#xff0c;那么到底怎么使用 foreach语句呢&#xff1f; …

ACM数论-素数

ACM数论——素数 素数定义&#xff1a; 质数&#xff08;prime number&#xff09;又称素数&#xff0c;有无限个。质数定义为在大于1的自然数中&#xff0c;除了1和它本身以外不再有其他因数&#xff0c;这样的数称为质数。例 子&#xff1a;2、3、5、7、11、13、17、19。&am…

机器视觉中彩色成像必须考虑的十个问题

来源&#xff1a;Imagination Tech在为你的产品开发最适合的机器视觉系统时&#xff0c;需要考虑很多因素&#xff0c;以下列出开发过程中需要考虑的一些问题&#xff1a;颜色准确性/差异化首先要考虑的是应用程序所需的颜色精度和差异程度。在某些应用中&#xff0c;机器视觉相…

嫦娥“挖土”归来有多难?看看中国首颗返回式卫星的故事

本文转载自“科技日报&#xff08;kjrbwx&#xff09;”&#xff0c;原标题《嫦娥“挖土”归来有多难&#xff1f;看看中国首颗返回式卫星的故事》&#xff0c;作者 | 吕炳宏 付毅飞2020年11月30日&#xff0c;嫦娥五号探测器在环月轨道上&#xff0c;成功实施着陆器上升器组合…

重磅,2020年度第十届吴文俊人工智能科学技术奖获奖名单公示

来源&#xff1a;科奖圈根据《吴文俊人工智能科学技术奖励条例》和《吴文俊人工智能科学技术奖励实施细则》相关规定&#xff0c;经全国各地方人工智能学会、协会及联盟&#xff0c;各高校及科研&#xff08;院&#xff09;所&#xff0c;学会各专业委员会及工作委会&#xff0…

理解 %IOWAIT (%WIO)

%iowait 是 “sar -u” 等工具检查CPU使用率时显示的一个指标&#xff0c;在Linux上显示为 %iowait&#xff0c;在有的Unix版本上显示为 %wio&#xff0c;含义都是一样的。这个指标常常被误读&#xff0c;很多人把它当作I/O问题的征兆&#xff0c;我自己每隔一段时间就会遇到对…

自由意志不存在?神经科学能证明不?

来源&#xff1a; 神经现实本文经授权摘自《认知科学对当代哲学的挑战》作者&#xff1a;李恒威神经科学能说明自由意志不存在吗?里贝特是人类意识和自由意志的实验研究领域的先驱性神经科学家&#xff0c;但驱使他开展意识的实证研究的根本动因是回应意识科学研究中的本体论问…

MySQL数据库order by 奇慢无比

今天遇到个奇葩的问题&#xff0c; sql 数据量很大 有where 和order by&#xff0c;不加order by 速度很快&#xff0c;加了就很慢 一、首先我们对这条sql执行查询计划&#xff1a; explain select t.order_id from book_order t ORDER BY t.order_id desc explain select t.…

PNAS “深度学习的科学”论文合集导读

来源&#xff1a;混沌巡洋舰今天的科学家对于机器可以学习做什么的想法与我们10年前完全不同。在图像处理、语音和视频处理、机器视觉、自然语言处理和经典的双人游戏中&#xff0c;特别是在过去的十年中&#xff0c;随着在一系列公共组织的挑战问题&#xff08;例如围棋&#…

s3c6410 jpeg编码 linux,S3C6410 裸机硬件JPEG解码

主函数的部分代码/**************************************************************************************************************************函数 : static PIC_ERROR OpenPictureFile(const char *FileName,u8 *buff,u32 FileMaxSize)*功能 : 打开一张…

注解原理

学习spring时&#xff0c;大量使用了注解&#xff0c;但一直对其底层实现机制不得其解&#xff1a; ref&#xff1a;http://www.cnblogs.com/Johness/archive/2013/04/17/3026689.html ref&#xff1a;https://www.jianshu.com/p/28edf5352b63 ref&#xff1a;http://www.cnblo…

C语言中关于字符数组输入,scanf没执行

问题&#xff1a;有时C语言中关于字符数组输入&#xff0c;有的scanf语句没执行。 未执行scanf的代码&#xff1a; #include<stdio.h> int main() {int n;int t0;scanf("%d",&n);char arr[n];int i;for(i0;i<n;i){scanf("%c",&arr[i]);…

清华微电子副所长尹首一:中国AI芯片的技术路线最全面

大数据文摘出品整理&#xff1a;牛婉杨12月1日&#xff0c;GTIC 2020 AI芯片创新峰会在京举办&#xff0c;本次峰会聚集了AI芯片以及各个细分赛道的产、学、研精英人士&#xff0c;共议AI芯片在中国半导体黄金时代的创新与未来。2020年对于AI芯片来说&#xff0c;是充满坎坷的一…

linux socket资源耗尽,TCP的socket资源被耗尽的问题

一、 故障现象部分机顶盒用户出现大面积登录APP时&#xff0c;界面停留在登陆页面&#xff0c;无反应。二、现象初步分析本次问题出现时&#xff0c;所有AAA出现了异常流量波动&#xff0c;在AAA异常流量段期间接到用户故障报障。此时主要表现在LVS集群显示真实的EPG 服务器不停…

演讲实录丨CAAI名誉副理事长杨强教授:人工智能的金融实践

杨强CAAI 名誉副理事长、微众银行首席人工智能官AAAI/ACM/IEEE/CAAI/AAAS Fellow转自中国人工智能学会CAAI原创 丨 作者杨强教授以下是杨强教授的演讲实录&#xff1a;今天的报告主要讲两个内容&#xff0c;一个是人工智能发展&#xff1b;另一个是如何在金融领域落地。刚才已经…

玩转python(2)多线程的历史2

线程这个概念早在多核CPU出现之前就提出来了&#xff0c;单核时代的多线程主要是为了让CPU尽量不处于空闲状态&#xff0c;使其计算能力始终能得到利用。但本质上讲&#xff0c;在任意时刻只有一个线程在执行。 尽管任意时刻只有一个线程在执行&#xff0c;但是依然有些问题需要…

2020年第五届中国通用人工智能年会

来源&#xff1a;知乎-刘凯-AGI现阶段&#xff0c;人工智能热正迅速“退烧”而回归理性&#xff0c;主流人工智能学界急切寻觅新的突破口。通用人工智能再次获得关注&#xff0c;并被期待成为下一轮技术引爆点。中国通用人工智能年会已成功举办四届&#xff0c;涉及计算机科学、…

post发送byte数组_KAFKA消息发送

消息发送的整体架构RecordAccumulator 主要用来缓存消息以便 Sender 线程可以批量发送&#xff0c;进而减少网络传输的资源消耗以提升性能。RecordAccumulator 缓存的大小可以通过生产者客户端参数 buffer.memory 配置&#xff0c;默认值为 33554432B&#xff0c;即32MB。如果生…