IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> IPv4路由表 -> 正文阅读

[网络协议]IPv4路由表

如下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

最后,删除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);
    }

内核版本 5.10

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章           查看所有文章
加:2021-11-09 19:59:31  更:2021-11-09 20:02:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年7日历 -2024/7/1 21:29:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码