Skip to content

IPv6 路由子系统

1. 模块架构

1.1 功能概述

IPv6 路由子系统负责查表和转发,与 IPv4 类似但使用不同的数据结构和查找算法。

1.2 关键源文件

文件作用
net/ipv6/route.cIPv6 路由实现
net/ipv6/fib6_rules.cIPv6 路由策略
net/ipv6/ip6_fib.cIPv6 FIB

2. 核心数据结构

2.1 struct rt6_info

c
// include/net/ip6_fib.h:180
struct rt6_info {
    struct dst_entry    dst;            // 通用目标入口
    struct rt6key       rt6i_dst;       // 目的地址
    struct rt6key       rt6i_src;       // 源地址
    struct in6_addr     rt6i_gateway;   // 网关
    struct inet6_dev   *rt6i_idev;     // 输入设备

    unsigned int        rt6i_flags;     // 标志

    struct fib6_table  *rt6i_table;    // 路由表
    struct fib6_node   *rt6i_node;     // FIB 节点

    struct rt6_info    *rt6i_next;     // 哈希链表
};

2.2 struct rt6key

c
// include/net/ip6_fib.h:150
struct rt6key {
    struct in6_addr addr;              // 地址
    unsigned int    plen;               // 前缀长度
};

2.3 struct fib6_table

c
// include/net/ip6_fib.h:60
struct fib6_table {
    struct hlist_node tb6_hlist;       // 哈希链表
    u32             tb6_id;           // 表 ID
    unsigned int    tb6_stamp;
    int             (*tb6_lookup)(struct fib6_table *,
                                  struct flowi6 *,
                                  struct fib6_result *,
                                  int);
    int             (*tb6_insert)(struct fib6_table *,
                                  struct fib6_result *,
                                  struct fib6_info *,
                                  gfp_t);
    void            *tb6_data;
};

2.4 struct fib6_node

c
// include/net/ip6_fib.h:100
struct fib6_node {
    struct fib6_node   *parent;        // 父节点
    struct fib6_node   *left;          // 左子节点
    struct fib6_node   *right;         // 右子节点
    struct fib6_node   *subtree;

    struct rt6_info     *leaf;         // 叶子节点

    struct list_head    info_list;     // 路由信息列表

    __be32              key[4];         // IPv6 地址
    unsigned char       bitlen;        // 位长度
    unsigned char       flags;         // 标志
};

3. 路由查找

3.1 ip6_route_output()

c
// net/ipv6/route.c:2100
struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
                                   struct flowi6 *fl6)
{
    struct dst_entry *dst;

    // 调用 fib6_lookup
    fib6_lookup(net, &fl6->flowi6_iif, fl6, &fl6->daddr, &res);

    dst = &res.rt6->dst;
    dst = dst_output(net, sk, dst, fl6);
    return dst;
}

3.2 fib6_lookup()

c
// net/ipv6/ip6_fib.c:400
int fib6_lookup(struct net *net, int oif, struct in6_addr *daddr,
                struct in6_addr *saddr, struct fib6_result *res)
{
    struct fib6_table *table;
    struct fib6_node *fn;

    // 获取路由表
    table = fib6_get_table(net, RT6_TABLE_MAIN);
    if (!table)
        return -ENETUNREACH;

    // 从根开始遍历
    fn = fib6_locate(table, daddr);

    // 匹配最长前缀
    while (fn) {
        if (fn->leaf)
            break;
        fn = fib6_walk_continue(fn);
    }

    // 返回结果
    *res = fib_SELECT_DEFAULT(fn);
}

4. 路由类型

c
// include/uapi/linux/fib_rule.h
enum {
    RTN_UNSPEC,       // 未知
    RTN_UNICAST,      // 单播
    RTN_LOCAL,        // 本地地址
    RTN_BROADCAST,    // 广播
    RTN_ANYCAST,      // 任播
    RTN_MULTICAST,    // 多播
    RTN_BLACKHOLE,    // 黑洞
    RTN_UNREACHABLE,  // 不可达
    RTN_PROHIBIT,     // 禁止
    RTN_THROW,        // 继续查找
    RTN_NAT,          // NAT
};

5. 路由缓存

5.1 rt6_cache_alloc()

c
// net/ipv6/route.c:800
struct rt6_info *rt6_cache_alloc(void)
{
    struct rt6_info *rt;

    rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
    if (!rt)
        return NULL;

    memset(rt, 0, sizeof(*rt));
    dst_init(&rt->dst, &rt6_dst_ops, 1);

    return rt;
}

5.2 rt6_insert_route()

c
// net/ipv6/route.c:900
int rt6_insert_route(struct fib6_table *table, struct rt6_info *rt)
{
    struct fib6_node *fn;

    // 插入到 fib6_node
    fn = fib6_locate(table, &rt->rt6i_dst.addr);

    // 添加到路由链表
    list_add_rcu(&rt->rt6i_rr链表, &fn->leaf_list);

    return 0;
}

6. 邻居发现路由

c
// 路由器发现添加的路由
// net/ipv6/route.c:1200
void rt6_add_dflt_router(struct net_device *dev, struct in6_addr *addr)
{
    struct rt6_info *rt;

    // 创建默认路由
    rt = rt6_cache_alloc();
    rt->rt6i_flags = RTF_UP | RTF_GATEWAY;
    rt->rt6i_gateway = *addr;
    rt->rt6i_dev = dev;

    // 插入路由表
    rt6_insert_route(table, rt);
}

7. 路由表操作

7.1 添加路由

c
// net/ipv6/route.c:1500
int ip6_route_add(struct fib6_config *cfg)
{
    struct rt6_info *rt;
    struct fib6_table *table;

    // 创建路由
    rt = rt6_alloc();
    if (!rt)
        return -ENOMEM;

    // 设置参数
    rt->rt6i_dst = cfg->fc_dst;
    rt->rt6i_src = cfg->fc_src;
    rt->rt6i_gateway = cfg->fc_gateway;

    // 获取表并插入
    table = fib6_get_table(cfg->fc_table);
    return fib6_add(table, fn, rt, cfg);
}

7.2 删除路由

c
// net/ipv6/route.c:1600
int ip6_route_del(struct fib6_config *cfg)
{
    struct fib6_table *table;
    struct fib6_node *fn;

    table = fib6_get_table(cfg->fc_table);
    fn = fib6_locate(table, &cfg->fc_dst);

    if (fn)
        return fib6_del(table, fn, rt);
}

基于 VitePress 构建