skb_buff 相关函数

在内核中操作 sk_buff 的函数非常丰富,主要可以分为分配与释放、数据指针操作、管理链表、克隆与复制这几大类。这些函数是处理网络数据包的基础,驱动或协议模块通过它们来安全地操作数据。

下面为你详细介绍每一类中最核心的函数及其用途。

1. 分配与释放

这是 sk_buff 生命周期的起点和终点。

函数 作用 关键说明
alloc_skb() 分配一个 sk_buff 结构体及其数据缓冲区。 最基础的分配函数,需指定大小和优先级(如 GFP_ATOMIC)。
dev_alloc_skb() 设备驱动专用的分配函数。 它是 alloc_skb() 的封装,通常用于接收路径,会在数据包开头预留空间(skb_reserve)以优化头部对齐。
kfree_skb() 释放 sk_buff 内核核心使用的释放函数,会检查引用计数,只在最后一个引用时真正释放内存。
dev_kfree_skb() / dev_kfree_skb_any() 驱动专用的释放函数。 驱动应使用这些变体,dev_kfree_skb_any() 可以在中断和进程上下文中安全调用。

2. 数据指针操作

这类函数用于移动指针,在协议栈各层添加或移除协议头,是核心操作。

函数 作用 关键说明
skb_reserve() 在数据缓冲区头部预留空间。 常用于接收数据包时,为各层协议头预留空间。它同时移动 datatail 指针。
skb_put() 在数据缓冲区尾部增加数据。 扩大 datatail 之间的有效数据区域。返回值指向新的数据起始位置。
skb_push() 在数据缓冲区头部增加数据。 data 指针向上移动,通常用于在发送时添加一个协议头(如以太网头)。返回值指向新的数据起始位置。
skb_pull() 从数据缓冲区头部移除数据。 data 指针向下移动,通常用于接收时剥离协议头。它会相应减小 len 值。
skb_trim() 从数据缓冲区尾部移除数据。 将数据包长度裁剪到指定值,常用于处理填充字节或截断数据包。

下图直观展示了这些指针操作函数如何改变 sk_buff 的结构:
skb_pull
head
headroom
已移除头部
data
data area
tail
end
tailroom
skb_push
head
headroom
data
新头部
新头部
data area
tail
end
tailroom
skb_put
head
headroom
data
data area (已用)
tail
end
tailroom
skb_reserve
head
headroom
data
data area
tail
end
tailroom
初始状态
head
headroom (保留区)
data
tail
end
tailroom (可用空间)

3. 队列管理操作

sk_buff 通常被组织成双向链表(sk_buff_head)进行管理。

函数 作用 关键说明
skb_queue_head() 将一个 skb 添加到队列头部。 带锁操作,保证原子性。
skb_queue_tail() 将一个 skb 添加到队列尾部。 最常用的入队操作,带锁。
skb_dequeue() 从队列头部取出一个 skb 最常用的出队操作,带锁。
skb_dequeue_tail() 从队列尾部取出一个 skb 带锁。
skb_insert() / skb_append() 在指定 skb 前后插入新 skb 带锁。
skb_unlink() skb 从当前队列中移除。 带锁。
skb_queue_purge() 清空整个队列并释放所有 skb 带锁。

注意 :上述所有队列操作函数都是锁安全的 。在中断上下文或已经持有自旋锁的情况下,可以使用不带锁的下划线版本(如 __skb_queue_tail()),这些版本在函数名前有双下划线前缀。

4. 克隆与复制

为了避免昂贵的拷贝,内核通过引用计数来共享数据。理解克隆与复制在涉及多路径或重传时非常重要。

函数 作用 关键说明
skb_clone() 克隆 sk_buff 结构体本身。 只复制元数据,不复制数据 。新 skb 指向同一个数据缓冲区。这是最快、最常用的方法。
skb_copy() 深度拷贝整个 sk_buff 和数据。 复制元数据和数据缓冲区,产生完全独立的副本。开销大,应尽量避免。
pskb_copy() 拷贝 sk_buff 和线性数据部分。 介于克隆和深度拷贝之间,只拷贝线性数据(datatail),分片数据(frags)被共享。

5. 高级操作与信息获取

这些函数用于处理更复杂的情况,如分散-聚集I/O(Scatter/Gather I/O)和校验和。

函数 作用 关键说明
skb_is_nonlinear() 判断 skb 是否使用分片(非线性)。 即数据是否部分存储在 frags 数组中,用于支持Scatter/Gather I/O。
skb_headlen() 获取线性部分的长度。 skb->len - skb->data_len
skb_checksum_help() 在软件中计算并填充数据包的校验和。 当硬件不支持特定校验和卸载时,驱动必须调用此函数。
skb_shared() / skb_cloned() 检查 skb 的共享/克隆状态。 在修改数据前,需检查这些函数以确保不会破坏其他引用者的数据。

总结

以上是内核中操作 sk_buff 最常用、最核心的函数。理解它们的分类和作用,特别是分配(alloc_skb)、指针操作(push/pull/put/reserve)、释放(kfree_skb)以及队列管理(queue/dequeue,是进行网络驱动开发或协议栈分析的基础。

相关推荐
A小辣椒1 天前
TShark:Wireshark CLI 功能
linux
A小辣椒1 天前
TShark:基础知识
linux
AlfredZhao2 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5203 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩3 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言