快捷搜索:  汽车  科技

ipv4路由表每条路由选项的含义:一篇讲解IPv4路由表

ipv4路由表每条路由选项的含义:一篇讲解IPv4路由表如果指定的路由表ID等于RT_TABLE_LOCAL,但是此命名空间中没有配置过IPv4策略路由,也使用main路由表,作为alias,参见fib_trie_table。这种情况下,fib_new_table会在调用自身,参数ID使用RT_TABLE_MAIN,获取main表的结构,赋值与alias。# ip route del 192.2.0.0/16 via 192.168.1.106 table main # # ping 192.2.0.1 PING 192.2.0.1 (192.2.0.1) 56(84) bytes of data. 23:50:55.690358 00:0c:29:1e:20:e3 > 00:60:e0:85:7a:06 ethertype IPv4 (0x0800) length 98: 192.168.1.140 >

如下IP命令添加路由表项,默认情况下路由添加在main路由表中:

# ip route add 192.2.0.0/16 via 192.168.1.106 # # ip route show table main 192.2.0.0/16 via 192.168.1.106 dev ens32

也可指定路由表,如下在local/default表中添加相同目的网络,但是网关不同的路由项:

# ip route add 192.2.0.0/16 via 192.168.1.1 table local # # ip route show table local 192.2.0.0/16 via 192.168.1.1 dev ens32 # # # ip route add 192.2.0.0/16 via 192.168.1.200 table default # # ip route show table default 192.2.0.0/16 via 192.168.1.200 dev ens32

下面使用PING命令测试到目的网段192.2.0.0/16,可见其使用的是local表中的路由项,而不是main表中项:

# tcpdump -i ens32 host 192.2.0.1 -n -e & // 后台启动tcpdump # # ping 192.2.0.1 PING 192.2.0.1 (192.2.0.1) 56(84) bytes of data. 23:05:53.330337 00:0c:29:1e:20:e3 > 00:90:27:fe:c9:34 ethertype IPv4 (0x0800) length 98: 192.168.1.140 > 192.2.0.1: ICMP echo request id 64942 seq 1 length 64 # # ip neigh show 192.168.1.1 dev ens32 lladdr 00:90:27:fe:c9:34 REACHABLE

以下删除local表中添加的路由,再执行ping操作,这次是main表中的路由生效,网关使用的是192.168.1.106:

# ip route del 192.2.0.0/16 via 192.168.1.1 table local # # ping 192.2.0.1 PING 192.2.0.1 (192.2.0.1) 56(84) bytes of data. 23:21:47.752867 00:0c:29:1e:20:e3 > 00:60:e0:6f:9c:e3 ethertype IPv4 (0x0800) length 98: 192.168.1.140 > 192.2.0.1: ICMP echo request id 528 seq 1 length 64 # # ip neigh show 192.168.1.106 dev ens32 lladdr 00:60:e0:6f:9c:e3 STALE

更多linux内核视频教程文档资料免费领取后台私信【内核】自行获取.

ipv4路由表每条路由选项的含义:一篇讲解IPv4路由表(1)

ipv4路由表每条路由选项的含义:一篇讲解IPv4路由表(2)

Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈-学习视频教程-腾讯课堂

最后,删除main中的路由,

# ip route del 192.2.0.0/16 via 192.168.1.106 table main # # ping 192.2.0.1 PING 192.2.0.1 (192.2.0.1) 56(84) bytes of data. 23:50:55.690358 00:0c:29:1e:20:e3 > 00:60:e0:85:7a:06 ethertype IPv4 (0x0800) length 98: 192.168.1.140 > 192.2.0.1: ICMP echo request id 2079 seq 1 length 64 # # ip neigh 192.168.1.200 dev ens32 lladdr 00:60:e0:85:7a:06 STALE

路由表创建
在添加表项时,没有指定路由表ID,或者指定的表ID等于0,内核使用main表RT_TABLE_MAIN,函数fib_trie_table分配一个新的fib_table结构,代表一个新的路由表。对于main表,将其制赋值给命名空间中的fib_main成员。最后将其链接到哈希桶fib_table_hash的对应链表中。

如果指定的路由表ID等于RT_TABLE_LOCAL,但是此命名空间中没有配置过IPv4策略路由,也使用main路由表,作为alias,参见fib_trie_table。这种情况下,fib_new_table会在调用自身,参数ID使用RT_TABLE_MAIN,获取main表的结构,赋值与alias。

对于default表,目前不太清楚其使用情况,在创建之后,内核将其赋值给命名空间的fib_default成员。

struct fib_table *fib_new_table(struct net *net u32 id) { struct fib_table *tb *alias = NULL; unsigned int h; if (id == 0) id = RT_TABLE_MAIN; tb = fib_get_table(net id); if (tb) return tb; if (id == RT_TABLE_LOCAL && !net->ipv4.fib_has_custom_rules) alias = fib_new_table(net RT_TABLE_MAIN); tb = fib_trie_table(id alias); if (!tb) return NULL; switch (id) { case RT_TABLE_MAIN: rcu_assign_pointer(net->ipv4.fib_main tb); break; case RT_TABLE_DEFAULT: rcu_assign_pointer(net->ipv4.fib_default tb); break; default: break; } h = id & (FIB_TABLE_HASHSZ - 1); hlist_add_head_rcu(&tb->tb_hlist &net->ipv4.fib_table_hash[h]); return tb;

对于main路由表,以及其它路由表,fib_trie_table的参数alias为空;但是对于local路由表,alias执向main表结构,就不用重新分配trie结构了。对于所有的路由表,都需要分配一个fib_table结构。

对于local路由表,其数据字段指向main路由表的数据字段。可见local表不是一个完全单独的路由表,其数据与main表是公用的。所以local路由表不需要进行以下对数据字段的初始化操作。

struct fib_table *fib_trie_table(u32 id struct fib_table *alias) { struct fib_table *tb; struct trie *t; size_t sz = sizeof(*tb); if (!alias) sz = sizeof(struct trie); tb = kzalloc(sz GFP_KERNEL); if (!tb) return NULL; tb->tb_id = id; tb->tb_num_default = 0; tb->tb_data = (alias ? alias->__data : tb->__data); if (alias) return tb; t = (struct trie *) tb->tb_data; t->kv[0].pos = KEYLENGTH; t->kv[0].slen = KEYLENGTH; #ifdef CONFIG_IP_FIB_TRIE_STATS t->stats = alloc_percpu(struct trie_use_stats); if (!t->stats) { kfree(tb); tb = NULL; } #endif return tb; 路由查找

如下内核的路由查询入口函数fib_lookup,可见其查询顺序为:路由策略->main路由表->default路由表。对local路由表的查询包含在main路由表查询中。

static inline int fib_lookup(struct net *net struct flowi4 *flp struct fib_result *res unsigned int flags) { struct fib_table *tb; int err = -ENETUNREACH; flags |= FIB_LOOKUP_NOREF; if (net->ipv4.fib_has_custom_rules) return __fib_lookup(net flp res flags); rcu_read_lock(); res->tclassid = 0; tb = rcu_dereference_rtnl(net->ipv4.fib_main); if (tb) err = fib_table_lookup(tb flp res flags); if (!err) goto out; tb = rcu_dereference_rtnl(net->ipv4.fib_default); if (tb) err = fib_table_lookup(tb flp res flags);

由函数fib_insert_alias可知,在trie树叶子节点中,路由表项时按照表ID由大到小排列的,如果local和main表中存在相同的路由,优先选择的是local表中的路由,宏RT_TABLE_LOCAL(255)大于RT_TABLE_MAIN(254)。

static int fib_insert_alias(struct trie *t struct key_vector *tp struct key_vector *l struct fib_alias *new struct fib_alias *fa t_key key) { if (!l) return fib_insert_node(t tp new key); if (fa) { hlist_add_before_rcu(&new->fa_list &fa->fa_list); } else { struct fib_alias *last; hlist_for_each_entry(last &l->leaf fa_list) { if (new->fa_slen < last->fa_slen) break; if ((new->fa_slen == last->fa_slen) && (new->tb_id > last->tb_id)) break; fa = last; } if (fa) hlist_add_behind_rcu(&new->fa_list &fa->fa_list); else hlist_add_head_rcu(&new->fa_list &l->leaf); }


导读-最新发表 - 我爱内核网 - 构建全国最权威的内核技术交流分享论坛

转载地址:一篇讲解IPv4路由表! - 圈点 - 我爱内核网 - 构建全国最权威的内核技术交流分享论坛

ipv4路由表每条路由选项的含义:一篇讲解IPv4路由表(3)

猜您喜欢: