源码静态路由实现原理?

访客 源码剖析 2

本文目录导读:

  1. 核心数据结构:路由表
  2. 查找算法:最长前缀匹配
  3. 数据包转发流程(源码执行顺序)
  4. 静态路由 vs 动态路由(源码层面的本质区别)

这是一个非常专业且偏底层网络/嵌入式开发的问题。

核心答案: 源码静态路由的实现原理,本质上是在操作系统的网络协议栈中维护一张由用户手动配置的、不会过期或动态变化的“路由表”,当数据包需要发送时,协议栈通过最长前缀匹配算法在这张表中查找下一跳地址和出接口,然后将数据包封装并转发。

查表匹配,按规则走,不学不老”。

以下从数据结构查找算法驱动流程三个层面,详细拆解其底层实现原理:

核心数据结构:路由表

在源码中(如 Linux 内核的 net/ipv4/route.cfib_trie.c),静态路由表不是简单的链表,而是一棵经过高度优化的Trie 树(字典树/前缀树)哈希表(Linux 4.x 后主要使用 FIB_TRIE)。

每个路由条目(struct fib_info)包含:

  • 目标网络:如 168.1.0/24
  • 子网掩码:如 255.255.0(决定了网络前缀长度)
  • 下一跳(Gateway/Gateway IP):要发给谁
  • 出接口(Output Interface):从哪个网卡发出去(如 eth0
  • 标志位:是否是直连、是否是黑洞、作用域等
  • 度量值(Metric):用于在多条静态路由中选优

查找算法:最长前缀匹配

这是路由器转发的核心算法,也是静态路由生效的关键。

场景举例: 假设你配置了两条静态路由:

  1. 168.1.0/24 -> 下一跳 0.0.1
  2. 168.1.128/25 -> 下一跳 0.0.2

现在有一个数据包目标 IP 为 168.1.200

  • 它同时匹配了第1条(/24)和第2条(/25)。
  • 原理机制:系统会计算两个条目的网络前缀长度(掩码长度)/25/24 更长(更精确)。
  • 结果:系统选择掩码更长、匹配更精确的那一条。168.1.200 会走第2条路由,发往 0.0.2

源码中的实现(伪代码逻辑)

// 简化版最长前缀匹配逻辑
static struct rt_entry *fib_table_lookup(struct fib_table *tb, __be32 daddr) {
    struct rt_entry *result = NULL;
    int longest_prefix_len = -1;
    // 遍历路由树(实际是Trie树查找)
    for each node in trie:
        if ( (daddr & node->mask) == node->network ) {
            // 如果前缀长度大于当前的记录
            if (node->prefix_len > longest_prefix_len) {
                longest_prefix_len = node->prefix_len;
                result = node; // 更新为更精确的匹配项
            }
        }
    return result; // 返回最精确匹配的项,如果没找到则返回 NULL (触发缺省路由或丢弃)
}

数据包转发流程(源码执行顺序)

当一个 IP 数据包从网卡(如 eth0)进入,或者由本机进程发出时,内核协议栈会执行以下步骤:

  1. IP 层接收

    • 网络驱动将数据传给 IP 层ip_rcv 函数)。
    • IP 层检查版本、校验和,然后决定是本机接收还是转发
  2. 路由查找

    • 调用 ip_route_inputip_route_output(取决于方向)。
    • 函数进入 FIB(转发信息库) 查找。fib_lookup 函数会传入目标 IP。
    • 匹配规则:先查最长前缀匹配,再比较度量值,会优先匹配直连网段(本地接口)。
  3. 决策

    • 命中:找到匹配的路由条目,得到 struct rtable(路由缓存结果),其中包含了下一跳 nh 和出接口 dev
    • 未命中:如果没找到,走缺省路由(0.0.0.0/0),如果缺省路由也没有配置,内核直接调用 icmp_send 发送“目标不可达”报文,并丢弃该数据包。
  4. ARP 解析与封装

    • 通过查找到的 next_hopdev,调用邻居子系统(neigh_output)。
    • IP to MAC:在 ARP 缓存中查找下一跳 IP 对应的 MAC 地址,如果没有,则发送 ARP 请求。
    • 二层封装:将 MAC 地址填入以太网帧头,然后通过 dev_queue_xmit 放入网卡的发送队列。

静态路由 vs 动态路由(源码层面的本质区别)

特性 静态路由 动态路由
配置来源 用户手动 ip route add,写入内核路由表 路由协议进程(如BGPd/OSPFd)通过 netlink socket 写入
数据结构 存放在内核 FIB 表中,永不超时 存放在内核 FIB 表中,带有有效期 / 老化时间
稳定机制 无,需要管理工具或脚本监控网络变化 路由协议内部有选路算法、邻居保活、路径回收机制
错误处理 下一跳不可达时,路由条目仍然存在,但会变为“未激活”或“禁止”(dead),数据包被丢弃 路由协议发现下一跳挂了,自动删除该路由并从其他路径重新计算

源码静态路由实现原理一句话总结: 在操作系统内核中,通过手工配置的数据结构(如 Trie 树),对每个 IP 数据包执行“最长前缀匹配”查找,然后根据查找到的固定结果(下一跳 + 出接口)进行二层封装并转发,整个过程不涉及任何网络协议的学习、协商或拓扑变化的动态适应。

标签: 路由查找

抱歉,评论功能暂时关闭!