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

`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.xdnf.cn/news/17655.html

相关文章:

  • 数学建模:控制预测类问题
  • 全面了解机器语言之kmeans
  • 010601抓包工具及证书安装-基础入门-网络安全
  • 【Matplotlib】中文显示问题
  • 企业级WEB应用服务器TOMCAT — WEB技术详细部署
  • 正点原子esp32s3探测土壤湿度
  • openpnp - 顶部相机如果超过6.5米影响通讯质量,可以加USB3.0信号放大器延长线
  • Effective C++ 条款34:区分接口继承和实现继承
  • 数据库面试题集
  • DFT的几点理解(二)
  • 计算二分类误差时的常见错误及解决方案
  • 农经权二轮延包—已有软件与后续研究
  • Spring之【详解AOP】
  • NLP 2025全景指南:从分词到128专家MoE模型,手撕BERT情感分析实战(第四章)
  • scanpy单细胞转录组python教程(三):单样本数据分析之数据标准化、特征选择、细胞周期计算、回归等
  • 制动电阻烧损记录学习
  • Spark执行计划与UI分析
  • JVM调优好用的内存分析工具!
  • jvm有哪些垃圾回收器,实际中如何选择?
  • 工业相机选择规则
  • leetcode经典题目——单调栈
  • 机器学习第八课之K-means聚类算法
  • Android 16 KB页面大小适配的权威技术方案总结
  • Android Camera 打开和拍照APK源码
  • Suno API V5 全面升级——多语言接入,开启 AI 音乐创作新时代
  • GPT‑5 重磅发布
  • 【开源】分层状态机(HFSM)解析:复杂逻辑的清晰表达与FPGA实现(附完整的Verilog交通灯案例及仿真)
  • Loki+Alloy+Grafana构建轻量级的日志分析系统
  • 随机向量正交投影定理(Orthogonal Projection Theorem, OPT)_学习笔记
  • 【YOLO学习笔记】YOLOv11详解