Skip to content

neighbour - 邻居子系统

1. 模块架构

1.1 功能概述

邻居子系统实现了 ARP (IPv4) 和 NDP (IPv6) 的核心功能,维护从 IP 地址到 MAC 地址的映射。

1.2 关键源文件

文件作用
net/core/neighbour.c邻居表实现
include/net/neighbour.h邻居定义
net/ipv4/arp.cARP 实现
net/ipv6/ndisc.cNDisc 实现

2. 核心数据结构

2.1 struct neighbour

c
// include/net/neighbour.h:113
struct neighbour {
    struct сосед next;        // 哈希链表
    struct rcu_head rcu;
    struct net_device *dev;   // 网络设备
    unsigned char   *ha;     // 硬件地址
    struct hh_cache *hh;
    __u8           primary_key[0];  // IP 地址作为主键
};

2.2 struct neigh_table

c
// include/net/neighbour.h:180
struct neigh_table {
    int family;                    // AF_INET/AF_INET6
    unsigned int key_len;          // 键长度
    __be16 protocol;              // 协议

    // 哈希表
    struct neigh_hash __rcu **hash_buckets;
    unsigned int        hash_buckets_log;
    unsigned int        hash_size;

    // 构造函数
    int (*constructor)(struct neighbour *);

    // 哈希函数
    u32 (*hash)(const void *pkey, const struct net_device *dev);

    // 验证
    int (*key_eq)(const struct neighbour *n, const void *pkey);

    // 状态和统计
    atomic_t         entries;
    atomic_t         allocs;
    int              max_clean_probes;
    int              gc_thresh;

    // 统计
    struct neigh_statistics __percpu *stats;

    // 参数
    struct neigh_parms parms;

    // 哈希表锁
    spinlock_t       lock;

    // 最近最少使用链表
    struct list_head   lru_list;

    // ID
    char            id[16];
};

2.3 NUD 状态

c
// include/uapi/linux/neighbour.h:34
enum {
    NUD_INCOMPLETE   = 0x01,  // 地址解析进行中
    NUD_REACHABLE    = 0x02,  // 最近确认可达
    NUD_STALE        = 0x04,  // 可达时间过期
    NUD_DELAY        = 0x08,  // 等待确认
    NUD_PROBE        = 0x10,  // 主动探测
    NUD_FAILED       = 0x20,  // 解析失败
    NUD_NOARP        = 0x40,  // 不需要解析
    NUD_PERMANENT    = 0x80,  // 永久条目
};

3. ARP/NDISC 初始化

3.1 ARP 表初始化

c
// net/ipv4/arp.c
static struct neigh_table arp_table = {
    .family = AF_INET,
    .key_len = 4,  // IPv4 地址长度
    .protocol = cpu_to_be16(ETH_P_IP),
    .hash = arp_hash,
    .key_eq = arp_key_eq,
    .constructor = arp_constructor,
    .id = "arp_cache",
};

3.2 NDisc 表初始化

c
// net/ipv6/ndisc.c
struct neigh_table nd_tbl = {
    .family = AF_INET6,
    .key_len = 16,  // IPv6 地址长度
    .protocol = cpu_to_be16(ETH_P_IPV6),
    .hash = ndisc_hash,
    .key_eq = ndisc_key_eq,
    .constructor = ndisc_constructor,
    .id = "ndisc_cache",
};

4. 邻居查找

4.1 neigh_lookup()

c
// net/core/neighbour.c:1280
struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
                              struct net_device *dev)
{
    struct neighbour *n;
    u32 hash_val;

    // 计算哈希
    hash_val = tbl->hash(pkey, dev) & (tbl->hash_size - 1);

    // 查找
    rcu_read_lock();
    n = lookup_neigh(tbl, pkey, hash_val);
    if (n && !atomic_inc_not_zero(&n->refcnt))
        n = NULL;
    rcu_read_unlock();

    return n;
}

4.2 neigh_create()

c
// net/core/neighbour.c:1400
struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
                               struct net_device *dev)
{
    struct neighbour *n;
    u32 hash_val;

    // 分配
    n = kmem_cache_alloc(tbl->kmem_cachep, GFP_ATOMIC);

    // 初始化
    n->dev = dev;
    n->primary_key = pkey;
    n->used = jiffies;

    // 调用协议特定构造函数
    err = tbl->constructor(n);

    // 添加到哈希表
    hash_val = tbl->hash(pkey, dev) & (tbl->hash_size - 1);
    __neigh_insert(hash_val, n, tbl);

    return n;
}

5. NUD 状态机

5.1 状态转换

                    +------------+
                    |  INCOMPLETE|
                    +------------+
                         |
          NS 丢失        | NS 发送
          或无响应         v
        +--------+  +--------+  +----------+
   +--->| STALE  |<-|DELAY   |<| REACHABLE|
   |    +--------+  +--------+  +----------+
   |       ^           |
   |       |           | 定时器到期
   |       |           v
   |       |       +--------+
   |       +-------| PROBE  |
   |               +--------+
   +----NA 收到------+--无响应

5.2 neigh_timer_handler()

c
// net/core/neighbour.c:940
void neigh_timer_handler(struct timer_list *t)
{
    struct neighbour *neigh = from_timer(neigh, t, timer);

    // 根据状态处理
    switch (neigh->nud_state) {
    case NUD_INCOMPLETE:
        // 发送 NS
        neigh->ops->solicit(neigh);
        break;

    case NUD_REACHABLE:
        // 转换为 STALE
        neigh_update(neigh, NULL, NUD_STALE);
        break;

    case NUD_DELAY:
        // 发送 NS,进入 PROBE
        neigh->ops->solicit(neigh);
        neigh->nud_state = NUD_PROBE;
        break;

    case NUD_PROBE:
        // 重传 NS
        neigh->ops->solicit(neigh);
        break;
    }
}

6. ARP 实现

6.1 arp_solicit()

c
// net/ipv4/arp.c:650
static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
{
    __be32 saddr;
    u8 dst_hw[ETH_ALEN];

    // 获取源地址
    if (skb && !inet_addr_type_dev_table(net, dev, ip_hdr(skb)->saddr))
        return;

    // 发送 ARP 请求
    arp_send(ARPOP_REQUEST, ETH_P_ARP, target_ip, dev, saddr,
             broadcast_hw, dev->dev_addr, NULL);
}

6.2 arp_rcv()

c
// net/ipv4/arp.c:1105
int arp_rcv(struct sk_buff *skb)
{
    struct arphdr *arp = arp_hdr(skb);

    // 查找或创建邻居条目
    neigh = __neigh_lookup(&arp_table, arp->ar_tip, dev);

    // 处理 ARP 操作
    switch (arp->ar_op) {
    case htons(ARPOP_REQUEST):
        // 请求:发送 ARP 回复
        arp_send_reply(arp->ar_sha, arp->ar_sip, dev, arp->ar_thi);
        break;
    case htons(ARPOP_REPLY):
        // 回复:更新邻居
        neigh->ops->update(neigh, arp);
        break;
    }
}

7. GC (垃圾回收)

7.1 neigh_forced_gc()

c
// net/core/neighbour.c:1600
int neigh_forced_gc(struct neigh_table *tbl)
{
    int evicted = 0;

    spin_lock_bh(&tbl->lock);

    // 遍历 LRU 列表
    list_for_each_entry_safe(neigh, next, &tbl->lru_list, list) {
        // 跳过永久条目
        if (neigh->nud_state & NUD_PERMANENT)
            continue;

        // 跳过正在使用的
        if (neigh->refcnt > 1)
            continue;

        // 删除
        __neigh_remove(neigh);
        evicted++;
    }

    spin_unlock_bh(&tbl->lock);
    return evicted;
}

7.2 GC 触发

c
// 条件触发:
// 1. 表大小超过 gc_thresh
// 2. 定时器周期性检查

基于 VitePress 构建