当前位置: 首页 > news >正文

Linux 路由表建立过程分析

Linux 路由表建立过程深度分析

一、工作原理

路由表是 Linux 网络栈的核心组件,用于决策数据包的转发路径。其建立过程分为三个层次:

  1. 内核初始化阶段

    • 自动创建本地路由表(local 表)
    • 为每个网络接口生成直连路由(scope link
    • 本地地址路由(scope host
  2. 用户空间配置

    • 静态路由:通过 ip route 或配置文件添加
    • 动态路由:通过守护进程(如 BIRD/FRR)注入
  3. 内核决策机制

    • 基于最长前缀匹配(LPM)算法
    • 多路由表支持(策略路由)
    • 路由缓存(已合并到主表)

二、实现机制与代码框架

核心路径: net/ipv4/route.cnet/ipv4/fib_*.c

发送Netlink消息
RTM_NEWROUTE
其他消息
用户空间
rtnetlink套接字
消息类型判断
路由添加流程
参数解析与验证
查找目标路由表
执行fib_table_insert
Trie树插入操作
创建路由节点
更新路由信息
通知路由更新
更新FIB完成
其他处理流程
详细流程解析:
  1. 用户空间发起请求

    • 通过ip route add命令或Netlink API发送路由添加请求
    • 消息类型:RTM_NEWROUTE (netlink消息头中的nlmsg_type)
  2. 内核接收处理

    • 入口函数:rtnetlink_rcv() (net/core/rtnetlink.c)
    static void rtnetlink_rcv(struct sk_buff *skb)
    {netlink_rcv_skb(skb, &rtnetlink_rcv_msg);
    }
    
  3. 路由添加流程

    • 核心函数:rtm_to_fib_config() (net/ipv4/fib_frontend.c)
    static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,struct nlmsghdr *nlh, struct fib_config *cfg)
    {// 解析netlink属性:目标网络、网关、设备等
    }
    
  4. 路由表操作

    • 路由表选择:fib_get_table() (net/ipv4/fib_trie.c)
    struct fib_table *fib_get_table(struct net *net, u32 id)
    {// 根据ID获取路由表(main表ID=254)
    }
    
  5. Trie树插入

    • 核心算法:trie_insert() (net/ipv4/fib_trie.c)
    static int fib_insert_node(struct trie *t, struct key_vector *tp,struct fib_alias *new, t_key key)
    {// 在LC-Trie中插入新节点// 处理节点分裂和合并
    }
    
  6. 路由信息更新

    • 创建路由信息结构:fib_create_info() (net/ipv4/fib_semantics.c)
    struct fib_info *fib_create_info(struct fib_config *cfg)
    {// 分配fib_info结构// 设置下一跳(fib_nh)、作用域(scope)等
    }
    
  7. 通知机制

    • 路由更新通知:rtmsg_fib() (net/ipv4/fib_frontend.c)
    static void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,int dst_len, u32 tb_id, struct nl_info *info)
    {// 通过netlink发送RTM_NEWROUTE通知
    }
    

关键代码流程:

  1. 路由添加入口rtnetlink_rcv() (net/core/rtnetlink.c)
  2. 路由表操作fib_table_insert() (net/ipv4/fib_trie.c)
  3. Trie 树操作trie_insert() (net/ipv4/fib_trie.c)
  4. 路由查找ip_route_input_slow() (net/ipv4/route.c)

三、核心数据结构

// 路由表抽象(include/net/ip_fib.h)
struct fib_table {u32         tb_id;          // 路由表ID(e.g. RT_TABLE_MAIN)int         (*tb_lookup)(...); // 查找函数struct trie *tb_data;        // Trie 树根节点
};// Trie 树节点(net/ipv4/fib_trie.c)
struct tnode {t_key key;                  // 关键键值unsigned long pos;          // 位位置struct tnode __rcu *child[0]; // 子节点
};// 路由信息(include/net/ip_fib.h)
struct fib_info {struct hlist_node fib_hash;int              fib_treeref;u32              fib_prefsrc; // 首选源地址unsigned char    fib_scope;  // 作用域struct fib_nh    fib_nh[0];  // 下一跳数组
};// 下一跳信息
struct fib_nh {struct net_device *nh_dev;  // 出口设备u32               nh_gw;    // 网关IP
};

四、路由添加实例代码

#include <arpa/inet.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>// 创建 netlink 路由消息
void add_route(const char *dst, int prefixlen, const char *gw, const char *dev) {int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);struct {struct nlmsghdr nh;struct rtmsg rt;char buf[1024];} req = {0};// 初始化 netlink 头req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;req.nh.nlmsg_type = RTM_NEWROUTE;// 设置路由属性req.rt.rtm_family = AF_INET;req.rt.rtm_dst_len = prefixlen;req.rt.rtm_table = RT_TABLE_MAIN;req.rt.rtm_scope = RT_SCOPE_UNIVERSE;req.rt.rtm_protocol = RTPROT_STATIC;req.rt.rtm_type = RTN_UNICAST;// 添加目标网络struct rtattr *rta = (struct rtattr *)((char *)&req + NLMSG_ALIGN(req.nh.nlmsg_len));rta->rta_type = RTA_DST;rta->rta_len = RTA_LENGTH(4);inet_pton(AF_INET, dst, RTA_DATA(rta));req.nh.nlmsg_len += rta->rta_len;// 添加网关或设备if (gw) {rta = (struct rtattr *)((char *)&req + NLMSG_ALIGN(req.nh.nlmsg_len));rta->rta_type = RTA_GATEWAY;rta->rta_len = RTA_LENGTH(4);inet_pton(AF_INET, gw, RTA_DATA(rta));req.nh.nlmsg_len += rta->rta_len;} else {rta = (struct rtattr *)((char *)&req + NLMSG_ALIGN(req.nh.nlmsg_len));rta->rta_type = RTA_OIF;rta->rta_len = RTA_LENGTH(4);int ifindex = if_nametoindex(dev);memcpy(RTA_DATA(rta), &ifindex, 4);req.nh.nlmsg_len += rta->rta_len;}// 发送到内核send(sock, &req, req.nh.nlmsg_len, 0);close(sock);
}int main() {// 添加路由:目标 10.1.0.0/24 通过网关 192.168.1.1add_route("10.1.0.0", 24, "192.168.1.1", NULL);return 0;
}

编译命令:gcc route_add.c -o route_add

五、常用工具与调试命令

  1. 路由管理工具

    # 查看路由表
    ip route show table main
    ip -6 route  # IPv6路由# 添加/删除路由
    ip route add 192.168.2.0/24 via 10.0.0.1 dev eth0
    ip route del default via 192.168.1.1# 策略路由
    ip rule add from 192.168.1.100 lookup custom_table
    
  2. 调试命令

    # 内核路由日志
    dmesg | grep "IPv4:"# 路由查找模拟
    ip route get 8.8.8.8 from 192.168.1.100 iif eth0# 路由表统计
    cat /proc/net/stat/rt_cache# Netlink 监控
    nlmon  # 需要加载 nlmon 驱动
    
  3. 动态调试

    # 启用内核调试
    echo 8 > /proc/sys/kernel/printk
    echo "file net/ipv4/* +p" > /sys/kernel/debug/dynamic_debug/control# Ftrace 跟踪
    echo function > /sys/kernel/tracing/current_tracer
    echo fib_table_lookup > /sys/kernel/tracing/set_ftrace_filter
    cat /sys/kernel/tracing/trace_pipe
    

####六、关键调试技巧

  1. 路由查找问题

    • 检查 ip route get 输出是否匹配预期
    • 验证反向路径过滤:sysctl net.ipv4.conf.all.rp_filter
    • 检查路由表ID:ip route show table all
  2. 路由表不一致

    • 比较 ip routecat /proc/net/route(十六进制格式)
    • 检查路由协议守护进程状态(如 BIRD/FRR)
  3. 内核崩溃分析

    • 使用 crash 工具检查 fib_info 结构
    • 分析 oops 日志中的函数调用栈

七、性能优化

  1. 路由表结构选择

    • 小规模网络:Hash 表
    • 大规模路由:LC-Trie(Linux 默认)
    • 超大规模:硬件卸载(如 DPDK)
  2. 路由缓存策略

    • 禁用已弃用的路由缓存:sysctl net.ipv4.route.flush=1
    • 优化垃圾回收参数:sysctl net.ipv4.route.gc_timeout
  3. 多核扩展

    • 使用每核路由表(Per-CPU Routing Tables)
    • 配置 RPS(Receive Packet Steering)

通过深入理解路由表建立机制,可有效诊断网络问题(如路由黑洞、转发环路),并优化大型网络环境下的路由性能。实际应用中需结合具体场景选择静态配置或动态路由协议(如 OSPF/BGP)。

http://www.dtcms.com/a/330490.html

相关文章:

  • 开疆智能Ethernet转ModbusTCP网关连接UR机器人配置案例
  • LeetCode 面试经典 150_数组/字符串_最后一个单词的长度(19_58_C++_简单)(反向遍历)
  • 百川开源大模型Baichuan-M2的医疗能力登顶第一?
  • 【机器人-开发工具】ROS 2 (4)Jetson Nano 系统Ubuntu22.04安装ROS 2 Humble版本
  • OpenBMC中C++策略模式架构、原理与应用
  • AI数据仓库的核心优势解析
  • 设计模式基础概念(行为模式):策略模式
  • 【java实现一个接口多个实现类通用策略模式】
  • [Oracle数据库] ORACLE基本DML操作
  • 【软件测试】自动化测试 — selenium快速上手
  • Java设计模式之《策略模式》
  • STM32L051C8与STM32L151C8的主要区别
  • visual studio调试cmake项目记录
  • 用飞算JavaAI一键生成电商平台项目:从需求到落地的高效实践
  • 远程影音访问:通过 cpolar 内网穿透服务使用 LibreTV
  • Mybatis学习笔记(九)
  • Spring Boot + Redis + 布隆过滤器防止缓存穿透
  • [已解决]当启动 Spring Boot 应用时出现 Using generated security password xxx提示
  • OpenCV 视频处理全解析
  • EI学术会议 | 可再生能源、智能电网、电力系统优化、能源存储技术
  • Linux系统Namespace隔离实战:dd/mkfs/mount/unshare命令组合应用
  • 缓存元数据损坏操作步骤(lvmcache修复)
  • 微软推出AI恶意软件检测智能体 Project Ire
  • 截断重要性采样(TIS)在医疗AI大模型训练中的优化路径
  • 嵌入式领域,ROM和RAM的区别
  • pytorch学习笔记-Loss的使用、在神经网络中加入Loss、优化器(optimizer)的使用
  • 基于SpringBoot+Vue的轻手工创意分享平台(WebSocket即时通讯、协同过滤算法、Echarts图形化分析)
  • 依托AR远程协助,沟通协作,高效流畅
  • 七、SpringBoot工程日志设置
  • [前端算法]动态规划