当前位置: 首页 > news >正文

`sk_buff` 结构体详解(包含全生命周期解析)

一、sk_buff 结构体解析

sk_buff(socket buffer)是 Linux 网络协议栈的核心数据结构,用于表示网络数据包的所有元信息和数据内容。

核心成员解析
struct sk_buff {// 数据缓冲区管理unsigned char *head;    // 分配内存的起始地址unsigned char *data;    // 当前协议层数据的起始地址unsigned char *tail;    // 当前协议层数据的结束地址unsigned char *end;     // 分配内存的结束地址// 长度信息unsigned int len;       // 当前数据总长度 (data 到 tail)unsigned int data_len;  // 分片数据长度 (当有分片时)// 协议栈信息__u16 protocol;         // 上层协议 (e.g., ETH_P_IP)__u16 transport_header; // 传输层头偏移__u16 network_header;   // 网络层头偏移__u16 mac_header;       // MAC 层头偏移// 网络设备信息struct net_device *dev; // 接收/发送的设备// 路由和转发struct dst_entry *dst;  // 路由缓存信息// 控制信息char cb[48];            // 控制缓冲区 (各协议私有数据)// 引用计数refcount_t users;       // 引用计数器// 分片管理struct sk_buff *next;   // 下一个分片 (用于GRO/GSO)
};
关键内存区域
      head                              end|                                |▼                                ▼
+-------+----------------+--------------+-------+
| headroom |   packet data   |  tailroom | 
+-------+----------------+--------------+-------+▲                ▲              ▲|                |              |mac_header      network_header   tail|           (e.g., IP头)        |data ─────────────────────────────┘

二、sk_buff 生命周期流程图

1. 接收路径生命周期 (RX)
物理设备/virtio后端网卡驱动协议栈应用程序数据包到达分配sk_buff (或使用预分配)填充数据到sk_buffnetif_receive_skb(skb)协议处理 (MAC→IP→TCP)数据就绪 (sock_queue_rcv_skb)recv() 读取数据释放sk_buff (kfree_skb)物理设备/virtio后端网卡驱动协议栈应用程序
2. 发送路径生命周期 (TX)
应用程序协议栈网卡驱动物理设备/virtio后端send() 发送数据分配sk_buff构建包头 (TCP→IP→MAC)dev_queue_xmit(skb)映射DMA区域添加到发送队列发送数据包发送完成中断释放sk_buff (dev_consume_skb_any)应用程序协议栈网卡驱动物理设备/virtio后端

三、关键操作函数解析

1. 核心创建/销毁函数
函数作用
alloc_skb()分配新的sk_buff(指定headroom大小)
dev_alloc_skb()为驱动优化的分配(额外16字节headroom)
kfree_skb()通用释放函数(处理引用计数)
dev_kfree_skb_any()驱动专用释放(可在中断上下文使用)
2. 数据操作函数
// 添加头部(移动data指针)
unsigned char *skb_push(skb, len);// 移除头部(移动data指针)
unsigned char *skb_pull(skb, len);// 添加尾部数据(移动tail指针)
unsigned char *skb_put(skb, len);// 移除尾部数据(移动tail指针)
void skb_trim(skb, len);
3. 分片管理函数
// 分片skb(用于GSO)
struct sk_buff *skb_segment(skb, features);// 合并skb(用于GRO)
int skb_gro_receive(struct sk_buff *head, struct sk_buff *skb);

四、生命周期关键节点详解

接收路径关键阶段
  1. 驱动层创建

    // 分配sk_buff(预分配或动态分配)
    skb = netdev_alloc_skb(dev, len);// 填充数据(DMA映射)
    skb_put(skb, pkt_len);
    memcpy(skb->data, pkt_data, pkt_len);
    
  2. 协议栈处理

    // 提交给协议栈
    netif_receive_skb(skb);// 协议处理(示例:IP层)
    ip_rcv(skb, dev, pt, orig_dev);
    
  3. 应用层消费

    // Socket层接收
    sock_queue_rcv_skb(sk, skb);// 应用读取后释放
    kfree_skb(skb);
    
发送路径关键阶段
  1. 协议栈创建

    // 分配sk_buff
    skb = alloc_skb(len + headroom, GFP_KERNEL);// 构建协议头
    skb_reserve(skb, headroom);
    skb_put(skb, data_len);
    memcpy(skb->data, user_data, data_len);
    
  2. 驱动层发送

    // 驱动发送入口
    start_xmit(skb, dev) {// 映射DMA区域dma_map_single(dev, skb->data, skb->len);// 添加到发送队列virtqueue_add_outbuf(vq, &sg, 1, skb);
    }
    
  3. 发送完成释放

    // 中断处理中释放
    while ((skb = virtqueue_get_buf(vq, &len))) {dma_unmap_single(dev, skb->data, skb->len);dev_consume_skb_any(skb); // 驱动负责释放!
    }
    

五、特殊场景处理

1. 零拷贝发送 (Zero-Copy TX)
mmap
用户空间
驱动环形缓冲区
直接DMA发送
发送完成后通知
  • 优势:避免用户态到内核态拷贝
  • APIsendfile()splice()
2. 零拷贝接收 (Zero-Copy RX)
// 1. 用户空间预注册内存区域
setsockopt(sock, SOL_PACKET, PACKET_RX_RING, &req);// 2. 驱动直接DMA到用户内存
while ((skb = virtqueue_get_buf(vq))) {// skb->data 指向用户空间内存// 无需拷贝直接提交协议栈
}
3. skb 克隆与拷贝
操作函数内存开销使用场景
完整拷贝skb_copy()需要修改原始数据
浅拷贝skb_clone()多路径转发
头部分离skb_unshare()协议栈修改包头

六、性能优化技巧

内存管理优化
  1. skb 池缓存

    // 初始化每CPU缓存
    netdev_alloc_skb() -> __alloc_skb() -> kmem_cache_alloc()
    
  2. 预分配策略

    // 接收路径预分配(virtio示例)
    while (virtqueue_num_free(vq) > 0) {skb = alloc_skb();virtqueue_add_inbuf(vq, skb);
    }
    
批量处理优化
  1. 发送批处理

    // 一次添加多个skb
    virtqueue_add_outbufs(vq, sg_array, num_skbs);// 延迟通知(积攒多个包后通知)
    if (packet_count > BATCH_SIZE) {virtqueue_kick(vq);
    }
    
  2. 接收软中断聚合

    // NAPI处理循环
    while (processed < budget) {skb = virtqueue_get_buf(vq);napi_gro_receive(napi, skb); // GRO聚合processed++;
    }
    

七、总结:sk_buff 设计哲学

  1. 统一数据包表示

    • 贯穿协议栈各层
    • 支持任意协议(以太网/IPv6/VxLAN等)
  2. 高效内存管理

    • headroom/tailroom 避免频繁重分配
    • 引用计数支持零拷贝转发
  3. 分层协议支持

    • 通过 mac_header/network_header 等实现协议栈分层处理
    • 支持分片(GSO)和重组(GRO)
  4. 生命周期明确

    • 发送路径:由驱动在发送完成后释放
    • 接收路径:由应用消费后释放
    • 转发路径:引用计数控制释放时机

sk_buff 的精心设计使其成为 Linux 网络栈高效处理每秒百万级数据包的核心基石,同时支持从嵌入式设备到数据中心的各种复杂场景。

http://www.dtcms.com/a/324118.html

相关文章:

  • How Websites Work 网站如何运作
  • 社交与职场中的墨菲定律
  • 2025年6月电子学会全国青少年软件编程等级考试(Python三级)真题及答案
  • DBAPI 实现不同角色控制查看表的不同列
  • 量子计算机实用化:从理论到现实的艰难跨越
  • 数据中心可视化:算力中枢智能运维
  • 编程基础之字符串——统计数字字符个数
  • JDBC的连接过程(超详细)
  • 【Docker-Day 12】揭秘容器网络:深入理解 Docker Bridge 模式与端口映射
  • Python爬虫-爬取政务网站的文档正文内容和附件数据
  • 【Linux | 网络】数据链路层
  • 电脑清理3步速成法
  • 三相LLC拓扑分析
  • CompletableFuture实现Excel sheet页导出
  • 产品经理入门 - 产品解决方案(需求分析、 功能优先级划分、功能价值、用户体验)
  • RabbitMQ面试精讲 Day 19:网络调优与连接池管理
  • NLP---IF-IDF案例分析
  • AI编程插件对比分析:CodeRider、GitHub Copilot及其他
  • 构建企业级Odoo 18 WMS——功能、架构与拓展蓝图
  • 宝塔面板部署sentinel
  • 【传奇开心果系列】基于Flet框架开发的增强版“Hello World“应用程序学习flet框架的拔高起点
  • 【后端】Java 8 特性 `User::getId` 语法(方法引用)介绍
  • Linux常用命令(后端开发版)
  • SQL(结构化查询语言)的四大核心分类
  • 【后端】Java 8 特性 Optional 可选类 介绍
  • Oracle 19C 查看卡慢的解决思路
  • Spring Boot整合knife4j实战
  • iceberg安装部署
  • imx6ull支持4G模块
  • C++高频知识点(十八)