Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 協議棧鄰居子系統垃圾回收機制深度解析

編輯:Linux 教學

鄰居子系統(Neighbour Subsystem)維護三層網絡地址到鏈路層地址的映射(ARP、NDP 等)。為防止緩存項無限增長耗盡內存,內核實現了基於定時器的垃圾回收(GC)機制,定期清理失效、長期未用條目。本文基於 Linux 2.6.21 內核源碼(net/core/neighbour.c)剖析 GC 定時器初始化、掃描邏輯、閾值控制、條目釋放全流程。

一、 GC 定時器初始化

// neigh_table_init() 中
init_timer(&tbl->gc_timer);
tbl->gc_timer.data = (unsigned long)tbl;
tbl->gc_timer.function = neigh_periodic_timer;
tbl->gc_timer.expires = jiffies + 1;  // 1 個 tick 後首次運行
add_timer(&tbl->gc_timer);

每個協議族(IPv4 arp_tbl、IPv6 nd_tbl 等)擁有獨立 neigh_table 及 GC 定時器。

二、 核心掃描函數 neigh_periodic_timer


static void neigh_periodic_timer(unsigned long arg) {
    struct neigh_table *tbl = (struct neigh_table *)arg;
    struct neighbour *n, **np;
    unsigned long expire, now = jiffies;

    NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);

    write_lock(&tbl->lock);

    // 1. 每 300 HZ 重新計算 reachable_time(隨機化防止同步風暴)
    if (time_after(now, tbl->last_rand + 300 * HZ)) {
        tbl->last_rand = now;
        struct neigh_parms *p;
        for (p = &tbl->parms; p; p = p->next)
            p->reachable_time = neigh_rand_reach_time(p->base_reachable_time);
    }

    // 2. 分桶掃描:每次處理一個 hash 桶
    np = &tbl->hash_buckets[tbl->hash_chain_gc];
    tbl->hash_chain_gc = (tbl->hash_chain_gc + 1) & tbl->hash_mask;  // 下次掃描下一桶

    while ((n = *np) != NULL) {
        write_lock(&n->lock);
        unsigned int state = n->nud_state;

        // 跳過永久條目、定時器處理中條目
        if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
            write_unlock(&n->lock);
            goto next_elt;
        }

        // 修正 used 時間不早於 confirmed
        if (time_before(n->used, n->confirmed))
            n->used = n->confirmed;

        // 3. 回收條件:引用計數=1 且 (FAILED 狀態 OR 超過 gc_staletime 未用)
        if (atomic_read(&n->refcnt) == 1 &&
            (state == NUD_FAILED ||
             time_after(now, n->used + n->parms->gc_staletime))) {
            *np = n->next;      // 從 hash 鏈表摘除
            n->dead = 1;
            write_unlock(&n->lock);
            neigh_release(n);   // 釋放資源
            continue;
        }

        write_unlock(&n->lock);
    next_elt:
        np = &n->next;
    }

    // 4. 重新裝填定時器:base_reachable_time / 2 / hash_bucket_num
    expire = tbl->parms.base_reachable_time >> 1;
    expire /= (tbl->hash_mask + 1);
    if (!expire) expire = 1;
    mod_timer(&tbl->gc_timer, now + expire);

    write_unlock(&tbl->lock);
}

三、 關鍵參數與閾值

可通過 sysctl 調整:

net.ipv4.neigh.default.gc_thresh1 = 128
net.ipv4.neigh.default.gc_thresh2 = 512
net.ipv4.neigh.default.gc_thresh3 = 1024

四、 條目狀態機與 GC 關係


NUD_INCOMPLETE  → (收到回應) → NUD_REACHABLE
    ↓ (超時/失敗)
NUD_FAILED      → (GC 回收)

NUD_REACHABLE   → (時間過期) → NUD_STALE
    ↓ (發送數據) → NUD_DELAY → (探測成功) → NUD_REACHABLE
                     ↓ (探測失敗) → NUD_PROBE → (失敗) → NUD_FAILED

NUD_PERMANENT   → 靜態配置,永不回收
NUD_NOARP       → 無 ARP 設備(如點對點),永不回收

GC 僅處理 refcnt == 1(僅 hash 表持有引用)的條目,防止正在使用的條目被釋放。

五、 強制立即 GC 觸發點

  1. neigh_create() 新建條目時,若 tbl->entries > gc_thresh3 → neigh_forced_gc()。
  2. neigh_alloc() 分配失敗時 → neigh_forced_gc() 後重試。
  3. 手動觸發:echo 1 > /proc/sys/net/ipv4/neigh/default/gc_interval(設置為 1 立即運行)。

六、 調試與監控

# 查看鄰居表統計
cat /proc/net/stat/arp_cache
# 或
cat /proc/net/stat/ndisc_cache

# 關鍵字段:
entries       當前條目數
allocs        分配次數
destroys      釋放次數
hash_grows    hash 擴容次數
lookups       查找次數
hits          命中次數
res_failed    解析失敗次數
gc_runs       GC 運行次數
Copyright © Windows教程網 All Rights Reserved
參數含義默認值 (IPv4)
gc_interval常規 GC 間隔(由動態計算覆蓋)30 HZ
gc_thresh1條目數 < thresh1:不強制 GC128
gc_thresh2條目數 > thresh2:5 秒內未刷新則強制 GC512
gc_thresh3條目數 > thresh3:拒絕新建,強制 GC1024
base_reachable_time基礎可達時間(隨機化後為 reachable_time)30 HZ
gc_staletime失效條目最大存活時間60 HZ