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 教學

鄰居子系統是 Linux 網絡協議棧中負責三層地址到鏈路層地址映射的核心模塊,支援 ARP (IPv4)、NDP (IPv6)、ATMARP 等協議。本文基於 Linux 2.6.21 源碼,系統解析 arp_init() 初始化流程、neigh_table 表結構、neighbour 條目結構、哈希表組織、參數配置體系。

一、 ARP 子系統初始化 arp_init()


void __init arp_init(void) {
    // 1. 鄰居表初始化(核心)
    neigh_table_init(&arp_tbl);

    // 2. 註冊協議包類型(接收 ARP 數據包)
    dev_add_pack(&arp_packet_type);

    // 3. 創建 /proc/net/arp 等 procfs 入口
    arp_proc_init();

    // 4. 註冊 sysctl 參數樹
    #ifdef CONFIG_SYSCTL
    neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4", NULL);
    #endif

    // 5. 註冊網絡設備事件通知器(設備上下線同步清理條目)
    register_netdevice_notifier(&arp_netdev_notifier);
}

二、 鄰居表結構 struct neigh_table


struct neigh_table {
    struct neigh_table *next;          // 全局鏈表指針
    int family;                        // 協議族:AF_INET, AF_INET6, AF_DECnet...
    int entry_size;                    // 條目大小:sizeof(neighbour) + key_len
    int key_len;                       // 關鍵字長度:IPv4=4, IPv6=16
    __u32 (*hash)(const void *pkey, const struct net_device *dev);  // 哈希函數
    int (*constructor)(struct neighbour *);  // 協議構造函數
    int (*pconstructor)(struct pneigh_entry *); // 代理條目構造
    void (*pdestructor)(struct pneigh_entry *);
    void (*proxy_redo)(struct sk_buff *skb);   // 代理 ARP 重發
    char *id;                          // 名稱:"arp_cache", "ndisc_cache"

    struct neigh_parms parms;          // 默認參數配置
    // GC 參數緊隨 parms 之後(內存佈局兼容)
    int gc_interval;                   // 常規 GC 間隔
    int gc_thresh1;                    // 閾值1
    int gc_thresh2;                    // 閾值2
    int gc_thresh3;                    // 閾值3(硬限制)
    unsigned long last_flush;          // 最後強制刷新時間

    struct timer_list gc_timer;        // 垃圾回收定時器
    struct timer_list proxy_timer;     // 代理定時器
    struct sk_buff_head proxy_queue;   // 代理隊列

    int entries;                       // 當前條目總數
    rwlock_t lock;                     // 表級鎖
    unsigned long last_rand;           // 最後隨機化時間
    struct neigh_parms *parms_list;    // 參數配置鏈表
    kmem_cache_t *kmem_cachep;         // 條目 slab 緩存
    struct neigh_statistics *stats;    // 統計計數器

    struct neighbour **hash_buckets;   // 哈希桶數組
    unsigned int hash_mask;            // 桶掩碼 (size-1)
    __u32 hash_rnd;                    // 哈希隨機種子
    unsigned int hash_chain_gc;        // GC 掃描桶索引

    struct pneigh_entry **phash_buckets; // 代理條目哈希表

    #ifdef CONFIG_PROC_FS
    struct proc_dir_entry *pde;        // procfs 目錄
    #endif
};

三、 鄰居條目結構 struct neighbour


struct neighbour {
    struct neighbour *next;            // 哈希桶鏈表指針
    struct neigh_table *tbl;           // 所屬表
    struct neigh_parms *parms;         // 參數配置(可繼承默認、可設備覆蓋)
    struct net_device *dev;            // 出接口設備
    unsigned long used;                // 最後使用時間
    unsigned long confirmed;           // 最後確認可達時間
    unsigned long updated;             // 最後更新時間
    __u8 flags;                        // 標志位
    __u8 nud_state;                    // 狀態機:NUD_INCOMPLETE, REACHABLE, STALE, DELAY, PROBE, FAILED, PERMANENT, NOARP
    __u8 type;                         // 目標類型:RTN_LOCAL, UNICAST, MULTICAST, BROADCAST...
    __u8 dead;                         // GC 標記
    atomic_t probes;                   // 剩餘探測次數
    rwlock_t lock;                     // 條目級鎖

    // 鏈路層地址緩存(緊湊對齊)
    unsigned char ha[(MAX_ADDR_LEN + sizeof(unsigned long) - 1) & ~(sizeof(unsigned long) - 1)];

    struct hh_cache *hh;               // 硬件頭緩存鏈表
    atomic_t refcnt;                   // 引用計數
    int (*output)(struct sk_buff *skb); // 輸出函數指針(狀態相關)
    struct sk_buff_head arp_queue;     // 待解析數據包隊列
    struct timer_list timer;           // 狀態定時器
    struct neigh_ops *ops;             // 協議操作向量

    u8 primary_key[0];                 // 彈性數組:關鍵字(IP 地址)
};

四、 參數配置結構 struct neigh_parms


struct neigh_parms {
    struct neigh_parms *next;          // 全局鏈表
    struct neigh_table *tbl;           // 所屬表
    int (*neigh_setup)(struct neighbour *); // 設備特定初始化
    void (*neigh_cleanup)(struct neighbour *);

    // 核心時間參數 (jiffies)
    int base_reachable_time;           // 基礎可達時間 (默認 30*HZ)
    int reachable_time;                // 實際可達時間 (隨機化後)
    int retrans_time;                  // 重傳間隔 (默認 1*HZ)
    int base_reachable_time;           // 重複字段?實為 gc_staletime
    int delay_probe_time;              // STALE→DELAY 延遲 (默認 5*HZ)
    int gc_staletime;                  // 失效條目最大存活 (默認 60*HZ)
    int queue_len;                     // arp_queue 最大長度 (默認 3)
    int ucast_probes;                  // 單播探測次數 (默認 3)
    int mcast_probes;                  // 多播探測次數 (默認 3)
    int app_probes;                    // 應用層探測次數 (默認 0)
    int proxy_qlen;                    // 代理隊列長度
    int proxy_delay;                   // 代理延遲
    int dead;                          // 參數集是否失效
};

五、 表初始化核心 neigh_table_init()


void __init neigh_table_init(struct neigh_table *tbl) {
    // 1. 分配 slab 緩存
    tbl->entry_size = ALIGN(tbl->entry_size, sizeof(unsigned long));
    tbl->kmem_cachep = kmem_cache_create(tbl->id, tbl->entry_size, 0,
                                         SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);

    // 2. 初始化默認參數
    tbl->parms.tbl = tbl;
    tbl->parms.neigh_setup = NULL;
    tbl->parms.neigh_cleanup = NULL;
    tbl->parms.base_reachable_time = 30 * HZ;
    tbl->parms.retrans_time = 1 * HZ;
    tbl->parms.gc_staletime = 60 * HZ;
    tbl->parms.delay_probe_time = 5 * HZ;
    tbl->parms.queue_len = 3;
    tbl->parms.ucast_probes = 3;
    tbl->parms.mcast_probes = 3;
    tbl->parms.app_probes = 0;
    tbl->parms_list = &tbl->parms;

    // 3. 哈希表分配(初始 32 桶)
    tbl->hash_buckets = kcalloc(32, sizeof(struct neighbour *), GFP_KERNEL);
    tbl->hash_mask = 31;
    tbl->hash_rnd = get_random_int();
    get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd));

    // 4. 初始化 GC 定時器
    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;
    add_timer(&tbl->gc_timer);

    // 5. 加入全局表鏈表
    write_lock_irq(&neigh_tbl_lock);
    tbl->next = neigh_tables;
    neigh_tables = tbl;
    write_unlock_irq(&neigh_tbl_lock);
}

六、 ARP 表全局實例


struct neigh_table arp_tbl = {
    .family       = AF_INET,
    .entry_size   = sizeof(struct neighbour) + 4,  // IPv4 地址 4 字節
    .key_len      = 4,
    .hash         = arp_hash,
    .constructor  = arp_constructor,
    .pconstructor = arp_pconstructor,
    .pdestructor  = arp_pdestructor,
    .proxy_redo   = arp_proxy_redo,
    .id           = "arp_cache",
};

七、 哈希函數 arp_hash


static __u32 arp_hash(const void *pkey, const struct net_device *dev) {
    const u32 *addr = pkey;
    return (*addr ^ (dev->ifindex << 8)) * arp_tbl.hash_rnd;
}

八、 關鍵設計總結

  1. 多表架構:每個協議族一張表,通過 neigh_tables 鏈表串聯,neigh_find_table(family) 查找。
  2. 參數繼承體系:默認參數 tbl->parms → 設備參數 in_dev->arp_parms → 條目參數 neigh->parms(clone 複製),支持 per-interface、per-neighbour 精細調優。
  3. Slab 緩存:kmem_cachep 加速頻繁分配/釋放條目,entry_size 包含彈性 primary_key。
  4. RCU 友好:哈希桶遍歷使用 rcu_read_lock,寫端加 tbl->lock,查找路徑無鎖。
  5. 統計計數器:neigh_statistics 記錄 allocs、destroys、hash_grows、lookups、hits、res_failed、gc_runs 等,/proc/net/stat/arp_cache 導出。
Copyright © Windows教程網 All Rights Reserved