http://blog.csdn.net/lickylin/article/details/38326719

从现在开始学习路由相关的代码,在分析代码之前, 我们还是先分析数据结构,把数据结构之间的关系理解了以后,再理解代码就相对轻松多了。本小节先分析路由相关的数据结构。内核里面大多模块定义的数据结构之间一般都是使用链表或者hash表实现连接操作。

对于路由表,相关的数据结构有fib_table、fn_hash、fn_zone、fib_node、fib_alias、fib_info、fib_nh等, 下面分别介绍这几个数据结构

路由表结构,该结构为一个路由表的抽象,包括路由表的id、路由添加函数、路由查找函数、路由删除函数等

  1. struct fib_table {
  2. /*使用hash链表将多个路由表变量链接在一起*/
  3. struct hlist_node tb_hlist;
  4. /*表id*/
  5. u32  tb_id;
  6. unsigned    tb_stamp;
  7. /*路由查找函数*/
  8. int  (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res);
  9. /*路由插入函数*/
  10. int  (*tb_insert)(struct fib_table *, struct fib_config *);
  11. /*路由项删除函数*/
  12. int  (*tb_delete)(struct fib_table *, struct fib_config *);
  13. int  (*tb_dump)(struct fib_table *table, struct sk_buff *skb,
  14. struct netlink_callback *cb);
  15. /*清空路由表的规则*/
  16. int  (*tb_flush)(struct fib_table *table);
  17. void     (*tb_select_default)(struct fib_table *table,
  18. const struct flowi *flp, struct fib_result *res);
  19. /*可变长数组,主要是用来指向掩码相关的hash数组*/
  20. unsigned char   tb_data[0];
  21. };

该结构主要用于描述以掩码划分的区域结构以及掩码区域之间的关系

对于ipv4来说,掩码可以为0-32共33种可能,因此对于一个fn_hash来说,则

定义了一个包含33个fn_zone的数组,而链表fn_zone_list,主要是将一个路由表里的

fn_zone链接在一起(以掩码大小的顺序排列,主要是在路由查找时,先匹配最长掩码对应的路由,以提高路由匹配的精确度)。

  1. struct fn_hash {
  2. struct fn_zone  *fn_zones[33];
  3. struct fn_zone  *fn_zone_list;
  4. };

以掩码划分的区域结构抽象,将掩码长度相同的所有路由放在同一个fn_zone中hash表中。

  1. struct fn_zone {
  2. /*指向下一个非空的fn_zone*/
  3. struct fn_zone   *fz_next;
  4. /*指向路由项关联的hash链表,对于掩码相关的目的ip地址,根据目的网络地址
  5. 的hash值,将新的fn_node节点插入到相应的hash链表中*/
  6. struct hlist_head   *fz_hash;   /* Hash table pointer   */
  7. /*fn_node结构变量的个数,fn_node并不能说是对一个路由项的抽象,可以看成对一个
  8. 目的网络地址的抽象,而对于相同的目的网络地址,可以根据tos、priority、mark值创建
  9. 不同的路由,所以一个fn_node结构中fn_alias才能算作是对一个路由项的抽象*/
  10. int  fz_nent;   /* Number of entries    */
  11. /*该fn_zone中fz_hash链表的个数*/
  12. int  fz_divisor;    /* Hash divisor  */
  13. /*fz_hash的mask值*/
  14. u32  fz_hashmask;   /* (fz_divisor - 1) */
  15. #define FZ_HASHMASK(fz)  ((fz)->fz_hashmask)
  16. /*以上两个值用于fz_hash数组的容量扩充相关*/
  17. /*该fn_zone对应的掩码长度*/
  18. int  fz_order;  /* Zone order    */
  19. /*根据fz_order而得到的掩码值*/
  20. __be32   fz_mask;
  21. /*获取该fn_zone对应的掩码值*/
  22. #define FZ_MASK(fz)  ((fz)->fz_mask)
  23. };

抽象为一个目的网络地址相同的所有路由项的基础结构,其中的fn_alias,表示该结构所包含的已存在的路由项的链表,fn_key为该结构对应的目的网络地址值,

用于和掩码长度相同的其他fib_node区分,对于同一个fn_zone里的fib_node,都链接到fn_zone->fz_hash中相应的hash表中

  1. struct fib_node {
  2. /*用于将hash值相同,且目的网络地址值不同,且网络掩
  3. 码相同的fib_node变量链接在一起*/
  4. struct hlist_node   fn_hash;
  5. struct list_head    fn_alias;
  6. __be32   fn_key;
  7. };

该结构可以理解为一个路由项的抽象。

当路由项的目的网络地址相同时,可以根据这个结构变量区分不同的路由项。包括tos、type、scope、state以及fib_info来区分一个路由项

方法:

1.首先根据tos、type、scope等确定一个fib_alias

2.当fib_alias确定以后,再根据priority等值确定一个fib_info,

3.根据fib_info确定出口设备与下一跳网关的ip地址。

  1. struct fib_alias {
  2. struct list_head    fa_list;
  3. struct rcu_head rcu;
  4. struct fib_info  *fa_info;
  5. u8   fa_tos;
  6. u8   fa_type;
  7. u8   fa_scope;
  8. u8   fa_state;
  9. };

而fa_scope表示路由的scope,取值范围如下:

RT_SCOPE_UNIVERSE:该选项用于所有通向非直连目的地的路由表项,即

应用层创建的路由中包含via的路由

RT_SCOPE_LINK:该选项用于目的地址为本地网络的路由项

RT_SCOPE_HOST:该选项用于路由为本机接口,

RT_SCOPE_NOWHERE:该选项用于路由不可到达

  1. enum rt_scope_t
  2. {
  3. RT_SCOPE_UNIVERSE=0,
  4. /* User defined values  */
  5. RT_SCOPE_SITE=200,
  6. RT_SCOPE_LINK=253,
  7. RT_SCOPE_HOST=254,
  8. RT_SCOPE_NOWHERE=255
  9. };

功能:主要是用来获取出口设备以及下一跳网关的数据结构,以及路由项的优先级,路由创建协议fib_protocol(RTPROTO_KERNEL、RTPROTO_BOOT、RTPROTO_STATIC等取值)。而fib_hash与fib_lhash则是将fib_info链接到对应的hash链表fib_info_hash[]与fib_info_laddrhash[]中去的。

  1. struct fib_info {
  2. /*这两个指针用于将该fib_info链接到hash链表中*/
  3. struct hlist_node   fib_hash;
  4. struct hlist_node   fib_lhash;
  5. int  fib_treeref;
  6. atomic_t     fib_clntref;
  7. /*标识是否将要释放该fib_info变量*/
  8. int  fib_dead;
  9. unsigned     fib_flags;
  10. int  fib_protocol;
  11. __be32   fib_prefsrc;
  12. /*优先级*/
  13. u32  fib_priority;
  14. u32  fib_metrics[RTAX_MAX];
  15. #define fib_mtu fib_metrics[RTAX_MTU-1]
  16. #define fib_window fib_metrics[RTAX_WINDOW-1]
  17. #define fib_rtt fib_metrics[RTAX_RTT-1]
  18. #define fib_advmss fib_metrics[RTAX_ADVMSS-1]
  19. /*fib_nh变量的个数*/
  20. int  fib_nhs;
  21. #ifdef CONFIG_IP_ROUTE_MULTIPATH
  22. int  fib_power;
  23. #endif
  24. #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
  25. u32  fib_mp_alg;
  26. #endif
  27. /*可变长度数组,用于动态申请fib_nh内存空间*/
  28. struct fib_nh    fib_nh[0];
  29. #define fib_dev  fib_nh[0].nh_dev
  30. };

包含下一跳网关及出口设备的结构

  1. struct fib_nh {
  2. /*数据包输出设备接口*/
  3. struct net_device   *nh_dev;
  4. /*将fib_nh变量链接在hash链表中*/
  5. struct hlist_node   nh_hash;
  6. /*包含该变量的fib_info变量*/
  7. struct fib_info  *nh_parent;
  8. unsigned     nh_flags;
  9. unsigned char    nh_scope;
  10. #ifdef CONFIG_IP_ROUTE_MULTIPATH
  11. int  nh_weight;
  12. int  nh_power;
  13. #endif
  14. #ifdef CONFIG_NET_CLS_ROUTE
  15. __u32    nh_tclassid;
  16. #endif
  17. /*出口设备的index*/
  18. int  nh_oif;
  19. /*下一跳网关地址*/
  20. __be32   nh_gw;
  21. };

而nh_hash是用来将fib_nh变量链接到对应的fib_info_devhash[]链表中的。

以上就是相应的数据结构分析,下面是这些数据结构之间的逻辑关系。没有给出fib_info_hash[]、fib_info_laddrhash[]与fib_info之间的,也没有给出fib_nh与fib_info_devhash之间的关系

以上就是路由相关的数据结构,下一节开始分析路由的添加与删除等功能。以上分析的数据结构没有包含路由缓存相关的数据结构,等到介绍到路由缓存时再进行分析。

Linux 路由 学习笔记 之一 相关的数据结构的更多相关文章

  1. Linux系统学习笔记:文件I/O

    Linux支持C语言中的标准I/O函数,同时它还提供了一套SUS标准的I/O库函数.和标准I/O不同,UNIX的I/O函数是不带缓冲的,即每个读写都调用内核中的一个系统调用.本篇总结UNIX的I/O并 ...

  2. linux kernel学习笔记-5内存管理_转

    void * kmalloc(size_t size, gfp_t gfp_mask); kmalloc()第一个参数是要分配的块的大小,第一个参数为分配标志,用于控制kmalloc()的行为. km ...

  3. Linux内核学习笔记二——进程

    Linux内核学习笔记二——进程   一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器 ...

  4. Linux命令学习笔记目录

    Linux命令学习笔记目录 最近正在使用,linux,顺便将用到的命令整理了一下. 一. 文件目录操作命令: 0.linux命令学习笔记(0):man 命令 1.linux命令学习笔记(1):ls命令 ...

  5. 尚硅谷韩顺平Linux教程学习笔记

    目录 尚硅谷韩顺平Linux教程学习笔记 写在前面 虚拟机 Linux目录结构 远程登录Linux系统 vi和vim编辑器 关机.重启和用户登录注销 用户管理 实用指令 组管理和权限管理 定时任务调度 ...

  6. linux 驱动学习笔记01--Linux 内核的编译

    由于用的学习材料是<linux设备驱动开发详解(第二版)>,所以linux驱动学习笔记大部分文字描述来自于这本书,学习笔记系列用于自己学习理解的一种查阅和复习方式. #make confi ...

  7. Linux内核学习笔记-2.进程管理

    原创文章,转载请注明:Linux内核学习笔记-2.进程管理) By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...

  8. Linux内核学习笔记-1.简介和入门

    原创文章,转载请注明:Linux内核学习笔记-1.简介和入门 By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...

  9. MySQL学习笔记-事务相关话题

    事务机制 事务(Transaction)是数据库区别于文件系统的重要特性之一.事务会把数据库从一种一致状态转换为另一个种一致状态.在数据库提交工作时,可以确保其要么所有修改都已经保存了,要么所有修改都 ...

随机推荐

  1. python__基础 : 多继承中方法的调用顺序 __mro__方法

    在多继承中,如果一个子类继承了两个平级的父类,而这两个父类有两个相同名字的方法,那么一般先继承谁,调用方法就调用先继承的那个父类的方法.如: class A: def test(self): prin ...

  2. Hive(6)-DML数据操作

    一. 数据导入 1. 语法 load data [local] inpath 'path' [overwrite] into table table_name [partition (partcol1 ...

  3. Vue 生产环境部署

    简要:继上次搭建vue环境后,开始着手vue的学习;为此向大家分享从开发环境部署到生产环境(线上)中遇到的问题和解决办法,希望能够跟各位VUE大神学习探索,如果有不对或者好的建议告知下:*~*! 一. ...

  4. go包管理工具glide使用方法

    golang没有官方最佳管理方案,在go的世界里存在大量的自制解决方案. go语言的包是没有中央库统一管理的,通过使用go get命令从远程代码库(github.com,goolge code 等)拉 ...

  5. 解决区间第K大的问题的各种方法

    例题:http://poj.org/problem?id=2104 最近可能是念念不忘,必有回响吧,总是看到区间第k大的问题,第一次看到是在知乎上有人面试被弄懵了后来又多次在比赛中看到.以前大概是知道 ...

  6. Angularjs 自定义指令 (下拉菜单)

    为什么要自定义控件?html的select 不是可以用么?以前我就是这么想的,当我接到特殊需求时,需要我自己写一个下拉控件. 这个需求就是将图表横向放大,由于H5不能控制设备转向,所以我将图表通过cs ...

  7. python--模块之基本

    模块的概念: 在计算机程序开发过程中,随着程序代码越来越多,在一个文件里代码就会越来越长,不利于维护.为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样每个文件包含的代码就相对较少. ...

  8. 北京Uber优步司机奖励政策(12月10日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  9. 在hive中查询导入数据表时FAILED: SemanticException [Error 10096]: Dynamic partition strict mode requires at least one static partition column. To turn this off set hive.exec.dynamic.partition.mode=nonstrict

    当我们出现这种情况时 FAILED: SemanticException [Error 10096]: Dynamic partition strict mode requires at least ...

  10. 创龙DSP6748开发板上电测试-第一篇

    1. 创龙DSP6748开发板测试.2980元的售价很高,我估计新的1200元比较合适,当然创龙定价是按照供需关系的.仿真器XDS100V2卖598元,真是狮子大张口. 2. 上电是5V-2A的电源. ...