fib: how ipv4 lookup route with rule route

概述

规则路由(rule route)

这部分详见ip rule命令帮助手册,
https://man7.org/linux/man-pages/man8/ip-rule.8.html
简要总结:

  • 支持多种形式的路由查找,不再仅仅局限于根据目的地址查找一种模式。
  • rule route采用了类似match-action模式, 不过rule route称之为SELECTORACTION
  • SELECTOR 支持多种形式,比如IP、PORT、进出网口、tos以及非操作(not)
  • ACTION 中几个重要的类型:
    • table:到指定的TABLE_ID对应的路由表里查找(所以这里要求必须支持多table)
    • nat: 支持IP地址nat
    • goto: 跳转到指定的rule route,通过这个可以做成多级级联。

几点说明

优先级

rule route是支持优先级的。 通过 ip rule show命令我们可以看到每条rule对应的优先级。添加rule时候,默认的是当前除0以外最高优先级的值-1, 即默认新建的rule优先级高。

1
2
3
4
5
6
7
8
9
10
11
12
root@martin-Standard-PC-Q35-ICH9-2009:/home/martin# ip rule show
0: from all lookup local
32763: from all sport 100-1000 goto 32766
32764: from 2.1.1.1/24 lookup 20000
32765: from 1.1.1.1/24 lookup 10000
32766: from all lookup main
32767: from all lookup default
root@martin-Standard-PC-Q35-ICH9-2009:/home/martin# ip r show table 10000
default via 192.168.100.1 dev veth0
root@martin-Standard-PC-Q35-ICH9-2009:/home/martin# ip r show table 20000
default via 192.168.122.200 dev enp1s0
root@martin-Standard-PC-Q35-ICH9-2009:/home/martin#

IPv4 rule route 配置示意图

没有嵌套

rule route里goto 可以反复多次嵌套多条rule,其他action均不能嵌套执行。
比如lookup,table查找的结果就是最终结果,不会再有其他跳转和嵌套。

内核代码解析

根据内核v6.6代码整理

数据结构

每个netns下有个IPv4相关的路由信息变量struct netns_ipv4 ipv4,
然后通过rules_ops指向IPv4对应的struct fib_rules_ops.
在这个ops下有一个rules_list链表,串联了所有的rule route。
每个rule对应一个结构体struct fib_rule

  • 每次增加rule规则时候,struct netns_ipv4里的变量fib_has_custom_rules被更新为true,以记录规则路由被启用了。
  • ops的初始化
    系统初始化时候,在fib4_rules_init里,通过复制模版创建一个ops,并把net信息记录到’ops’里。
    这个新创建的’ops’又被挂到’net’下的rule_ops链表里. 最后这个ops被保存到’IPv4’下的rules_ops
    1
    2
    3
    4
    5
    6
    fib4_rules_init
    --> fib_rules_register(&fib4_rules_ops_template, net)
    --> --> ops = kmemdup && ops->fro_net = net ;//复制模版创建一个ops,并把net信息记录到ops里。
    --> --> __fib_rules_register
    --> net->ipv4.rules_ops = ops;
    --> net->ipv4.fib_has_custom_rules = false;

IPv4 rule route 配置示意图

1
2
3
4
5
 61 struct net {
...
125 struct list_head rules_ops;
...
134 struct netns_ipv4 ipv4;
1
2
3
4
5
6
7
8
9
10
44 struct netns_ipv4 {
...
59 #ifdef CONFIG_IP_MULTIPLE_TABLES
60 struct fib_rules_ops *rules_ops;
61 struct fib_table __rcu *fib_main;
62 struct fib_table __rcu *fib_default;
63 unsigned int fib_rules_require_fldissect;
64 bool fib_has_custom_rules;
65 #endif
66 bool fib_has_custom_local_routes;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 60 struct fib_rules_ops {
61 int family;
62 struct list_head list;
...
74 int (*match)(struct fib_rule *,
75 struct flowi *, int);
76 int (*configure)(struct fib_rule *,
77 struct sk_buff *,
78 struct fib_rule_hdr *,
79 struct nlattr **,
80 struct netlink_ext_ack *);
...
92
94 struct list_head rules_list;
...
98 };
1
2
3
4
5
6
7
8
9
10
11
 20 struct fib_rule {
21 struct list_head list;
22 int iifindex;
...
27 u32 table;
28 u8 action;
33 __be64 tun_id;
34 struct fib_rule __rcu *ctarget;
35 struct net *fr_net;
...
47 };

函数调用关系

IPv4路由查找的关键函数
+ ip_route_output_flow:路由查找的入口函数
+ fib_table_lookup: 在一个具体table里,查找路由
tcp/udp/icmp/raw等类型的socket发送数据时候, 先调用到函数ip_route_output_flow,进而调用到fib_lookup,在这里通过宏CONFIG_IP_MULTIPLE_TABLES并分两种场景支持多table单table

  • 单table:只有一个main路由table表,不支持多table。`
  • 多table: 支持多个table。这是支持规则路由的一起必要条件。

case 1