Skip to content

dst_entry - 路由缓存条目

1. 模块架构

1.1 功能概述

dst_entry 是内核路由子系统的核心数据结构,用于缓存路由查找结果。

1.2 关键源文件

文件作用
net/core/dst.cdst_entry 实现
include/net/dst.hdst_entry 定义
include/net/route.hIPv4 路由
include/net/ip6_fib.hIPv6 路由

2. 核心数据结构

2.1 struct dst_entry

c
// include/net/dst.h:64
struct dst_entry {
    struct rcu_head     rcu;
    struct dst_entry    *child;         // 子路由
    struct dst_entry    *next;          // 哈希链表

    unsigned long       expires;        // 过期时间
    unsigned short      flags;          // 标志
    unsigned short      obsolete;       // 废弃标志
    int                 error;          // 错误码

    struct net_device   *dev;          // 输出设备
    struct dst_ops      *ops;           // 操作函数

    // 输入/输出回调
    int (*input)(struct sk_buff *);
    int (*output)(struct sk_buff *);

    // 邻居
    struct neighbour    *neighbour;

    // 统计
    unsigned long       lastuse;
    unsigned long       rate_tokens;
    int                 rate;
    struct list_head    dst_list;       // dst 链表
};

2.2 struct dst_ops

c
// include/net/dst.h:120
struct dst_ops {
    unsigned short family;              // 地址族
    unsigned int kmem_cachep;
    unsigned int flags;

    // 销毁
    void (*destroy)(struct dst_entry *);

    // 绑定
    void (*ifdown)(struct dst_entry *, struct net_device *dev, int how);

    // 发送
    struct dst_entry *(*link_failure)(struct sk_buff *);

    // 重新评估
    int (*local_out)(struct net *net, struct sock *sk, struct sk_buff *skb);

    // Neighbor
    struct neighbour* (*neigh_lookup)(const struct dst_entry *dst,
                                      struct flowi *fl,
                                      __be32 saddr);

    // 克隆
    struct dst_entry* (*clone)(struct dst_entry *dst);

    struct module       *owner;
};

3. IPv4 dst_entry

3.1 struct rtable

c
// include/net/route.h:70
struct rtable {
    struct dst_entry    dst;            // 必须是第一个
    int                 rt_genid;       // 路由代际
    unsigned int        rt_flags;       // 路由标志
    __u16               rt_type;        // 路由类型
    __be32              rt_dst;         // 目的地址
    __be32              rt_src;        // 源地址
    __be32              rt_gateway;     // 网关

    struct rt_key {
        __be32           src;
        __be32           dst;
        unsigned int     iif;
        __u8             tos;
        __u8             scope;
    } rt_key;
};

3.2 IPv4 dst_ops

c
// net/ipv4/route.c:600
static struct dst_ops ipv4_dst_ops = {
    .family = AF_INET,
    .kmem_cachep = &rtable_cache,
    .flags = DST_HOST,
    .destroy = ip_rt_dst_destroy,
    .ifdown = ip_rt_ifdown,
    .link_failure = ip_rt_link_failure,
    .local_out = ip_local_out,
    .neigh_lookup = ip_neigh_gw_output,
    .clone = ip_rt_clone,
    .owner = THIS_MODULE,
};

4. IPv6 dst_entry

4.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;     // 哈希链表
};

4.2 rt6_dst_ops

c
// net/ipv6/route.c:400
static struct dst_ops rt6_dst_ops = {
    .family = AF_INET6,
    .kmem_cachep = &rt6_info_cache,
    .flags = DST_HOST | DST_IP6,
    .destroy = ip6_dst_destroy,
    .ifdown = ip6_dst_ifdown,
    .link_failure = ip6_link_failure,
    .local_out = ip6_local_out,
    .neigh_lookup = ip6_neigh_lookup,
    .clone = ip6_rt_clone,
    .owner = THIS_MODULE,
};

5. 缓存管理

5.1 dst_cache

c
// include/net/dst.h:200
struct dst_cache {
    struct dst_cache_pcpu {
        struct dst_entry *dst;
        unsigned long lastuse;
    } __percpu *pcpu;
};

5.2 dst_cache_get()

c
// net/core/dst.c:200
struct dst_entry *dst_cache_get(struct dst_cache *dst_cache)
{
    struct dst_cache_pcpu *cpu;
    struct dst_entry *dst;

    cpu = get_cpu_var(dst_cache->pcpu);
    dst = rcu_dereference(cpu->dst);

    if (dst && !dst->obsolete &&
        time_before(jiffies, dst->lastuse + DST_CACHE_TIMEOUT))
        return dst;

    return NULL;
}

5.3 dst_cache_set()

c
// net/core/dst.c:250
void dst_cache_set(struct dst_cache *dst_cache, struct dst_entry *dst)
{
    struct dst_cache_pcpu *cpu;

    cpu = this_cpu_ptr(dst_cache->pcpu);
    rcu_assign_pointer(cpu->dst, dst);
    cpu->lastuse = jiffies;
}

6. 垃圾回收

6.1 dst_gc()

c
// net/core/dst.c:300
static void dst_gc(void)
{
    struct dst_entry *dst, *next;
    unsigned long now = jiffies;

    spin_lock_bh(&dst_default_lock);

    // 遍历 dst_list
    list_for_each_entry_safe(dst, next, &dst_list, dst_list) {
        // 检查过期
        if (dst->expires && time_after_eq(now, dst->expires)) {
            // 释放
            dst_release(dst);
        }
    }

    spin_unlock_bh(&dst_default_lock);
}

6.2 触发条件

c
// 触发 GC 的条件:
// 1. 路由缓存条目超过阈值
// 2. 定时器周期性检查
// 3. 内存压力时

7. 使用流程

7.1 查找

c
// dst = ip_route_output(dev_net(dev), daddr, saddr, tos, mark);
// dst_output() 调用 dst->output()

7.2 释放

c
// 使用后必须释放
dst_release(dst);

// 如果 refcnt 为 0,会调用 ops->destroy()

8. DST 标志

c
// include/net/dst.h:30
#define DST_HOST         0x0001   // 主机路由
#define DST_NOPOLICY     0x0004   // 不进行策略路由
#define DST_NOXFRM       0x0008   // 不进行 ipsec 转换
#define DST_NOCACHE      0x0010   // 不缓存
#define DST_FAKE_RTABLE  0x0020   // 假路由表

基于 VitePress 构建