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 核心網路數據結構深度解析:sk_buff 結構佈局與核心操作函數

編輯:Linux 教學

sk_buff(簡稱 skb)是 Linux 核心網路子系統中最核心的數據結構,貫穿從驅動層到傳輸層的所有數據流轉。本文詳細解析 sk_buff 的結構佈局、指針語義以及常用操作函數的實現邏輯。

sk_buff 結構詳細佈局

Linux 2.6.21 中 sk_buff 定義(include/linux/skbuff.h)包含以下關鍵字段:

鏈表與引用管理

struct sk_buff {
    struct sk_buff *next;      // 鏈表下一個
    struct sk_buff *prev;      // 鏈表上一個
    struct sk_buff_head *list; // 所屬鏈表頭
    struct sock *sk;           // 關聯 socket(傳輸層)
    struct timeval stamp;      // 時間戳
    atomic_t users;            // 引用計數
    // ...
}

設備指針三元組

struct net_device *dev;        // 發送/接收設備
struct net_device *input_dev;  // 接收設備
struct net_device *real_dev;   // 真實物理設備(虛擬設備場景)

協議層指針聯合體

// 傳輸層頭部指針
union {
    struct tcphdr *th;
    struct udphdr *uh;
    struct icmphdr *icmph;
    // ...
} h;

// 網絡層頭部指針
union {
    struct iphdr *iph;
    struct ipv6hdr *ipv6h;
    struct arphdr *arph;
} nh;

// 鏈路層頭部指針
union {
    unsigned char *raw;
} mac;

數據區域管理指針(核心)

unsigned char *head;  // 分配緩衝區起始地址
unsigned char *data;  // 有效數據起始地址(頭部空間預留)
unsigned char *tail;  // 有效數據結束地址
unsigned char *end;   // 分配緩衝區結束地址

unsigned int len;      // 數據總長度 (data 到 tail)
unsigned int data_len; // 分片數據長度
unsigned int mac_len;  // 鏈路層頭部長度
unsigned int truesize; // 實際佔用內存大小

內存佈局關係:

head ------------------------------------------- end
  |          |                    |             |
  |  headroom |     數據區域        |  tailroom  |
  |          |  (data 到 tail)     |             |
  data ---------------------------- tail

核心操作函數詳解

分配與釋放

函數功能關鍵行為
alloc_skb(size, gfp_mask)分配新 SKB分配 head 緩衝區,data=tail=head+headroom
skb_clone(skb, gfp_mask)克隆 SKB共享 head/data/tail/end 緩衝區,增加 users 引用計數,標記 cloned=1
skb_copy(skb, gfp_mask)深度拷貝分配新緩衝區,完整拷貝數據與元數據,獨立引用計數
kfree_skb(skb)釋放 SKB遞減 users,歸零時釋放緩衝區與結構體

數據區域調整


// 尾部擴展:tail 向後移動 len,返回舊 tail 位置(用於填充數據)
unsigned char *skb_put(struct sk_buff *skb, unsigned int len)

// 頭部擴展:data 向前移動 len,返回新 data 位置(用於添加頭部)
unsigned char *skb_push(struct sk_buff *skb, unsigned int len)

// 頭部預留:data 和 tail 同時向後移動 len(預留頭部空間)
void skb_reserve(struct sk_buff *skb, unsigned int len)

// 尾部縮減:tail 向前移動 len
void skb_trim(struct sk_buff *skb, unsigned int len)

// 頭部縮減:data 向後移動 len(移除頭部)
unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)

空間查詢

int skb_headroom(const struct sk_buff *skb)  // data - head:頭部可用空間
int skb_tailroom(const struct sk_buff *skb)  // end - tail:尾部可用空間

驅動層與協議棧的交互語義

  • 接收路徑:驅動分配 SKB,skb_reserve(skb, NET_IP_ALIGN) 預留 2 字節對齊,DMA 填充數據區,skb_put(skb, len) 更新尾部,skb->protocol = eth_type_trans(skb, dev) 解析協議類型並移動 data 指針跳過 MAC 頭。
  • 發送路徑:上層構建 SKB,預留足夠 headroom 供驅動添加硬件頭部,驅動調用 skb_push 添加封裝頭,最終調用 dev->hard_start_xmit。
  • 分片處理:大數據包通過 skb_shinfo(skb)->frags 管理分片頁面,data_len 記錄分片總長,len = head_len + data_len。

進階字段:控制緩衝區與特性標記

char cb[40];              // 各層私有控制信息(跨層需 skb_clone)
unsigned char pkt_type;   // PACKET_HOST/BROADCAST/MULTICAST/OTHERHOST
unsigned char ip_summed;  // CHECKSUM_NONE/UNNECESSARY/COMPLETE/HARDWARE
__u32 priority;           // QoS 優先級
unsigned short protocol;  // 協議類型 (ETH_P_*)
// Netfilter 相關
unsigned long nfmark;
struct nf_conntrack *nfct;
struct nf_bridge_info *nf_bridge;
// 流控相關
#ifdef CONFIG_NET_SCHED
__u32 tc_index;      // 流控分類索引
__u32 tc_verd;       // 流控裁決
__u32 tc_classid;    // 流控類別 ID
#endif

總結

sk_buff 以靈活的指針佈局實現了零拷貝、分層解析、分片管理等核心能力。掌握 head/data/tail/end 四指針語義與 skb_put/push/pull/reserve 操作語義,是理解 Linux 網路子系統數據流轉的基礎。

Copyright © Windows教程網 All Rights Reserved