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,是进行网络驱动开发或协议栈分析的基础。

相关推荐
黑蛋同志9 小时前
Ubuntu安装llama.cpp
linux·ubuntu·llama
yy_xzz9 小时前
【Linux开发】 Linux 信号处理——预防僵尸进程
linux·运维·信号处理
123过去17 小时前
wifi-honey使用教程
linux·网络·测试工具
Deitymoon19 小时前
linux——孤儿进程和僵尸进程
linux
Linux运维技术栈20 小时前
生产环境Linux应用目录迁移至LVM独立分区 标准化实战方案
linux·运维·服务器·lvm·逻辑卷
feasibility.21 小时前
SSH Agent Forwarding 与 tmux 排障笔记
linux·运维·服务器·经验分享·笔记·ssh
ShawnLiaoking21 小时前
Linux 会话窗口常开
linux·运维·服务器
230万光年的思念21 小时前
向日葵远程控制ubuntu24一直显示连接中
linux
IMPYLH1 天前
Linux 的 dir 命令
linux·运维·服务器·数据库
fanged1 天前
操作系统番外1(Linux的测试体系)(TODO)
linux·运维·服务器