元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
进程管理
▶
进程调度
调度策略
完全公平调度器
实时调度机制
▶
进程通信
信号机制
共享内存
管道与命名管道
▶
进程状态
上下文切换
僵尸进程处理
进程生命周期
▶
内存管理
▶
虚拟内存
页表机制
地址空间布局
TLB管理
▶
物理内存
伙伴系统
slab分配器
内存碎片处理
▶
文件系统
▶
VFS抽象层
inode机制
文件描述符
挂载机制
▶
具体文件系统
Ext4日志机制
Btrfs特性
Proc文件系统
▶
设备驱动
▶
驱动模型
设备树解析
sysfs接口
热插拔处理
▶
网络栈
▶
协议栈架构
sk_buff结构
Netfilter框架
套接字实现
▶
内核同步机制
▶
锁机制
自旋锁实现
RCU机制
Mutex与信号量
▶
启动过程
▶
引导阶段
GRUB交互
内核解压缩
早期初始化
▶
系统调用
▶
调用机制
陷入门实现
vsyscall优化
安全审计
▶
虚拟化和容器支持
▶
容器技术
命名空间隔离
cgroups实现
OverlayFS原理
发布时间:
2025-03-23 11:03
↑
☰
# Linux网络栈sk_buff结构 ## 概述 sk_buff(socket buffer)是Linux网络协议栈中最重要的数据结构之一,它用于在网络协议栈的各层之间传递数据包。sk_buff结构体包含了数据包本身以及与之相关的控制信息,为网络数据的处理提供了统一的接口。 ## 基本结构 ### 1. 数据结构定义 ```c struct sk_buff { /* 链表相关 */ struct sk_buff *next; struct sk_buff *prev; struct sock *sk; /* 时间戳 */ ktime_t tstamp; /* 网络设备相关 */ struct net_device *dev; unsigned int len; unsigned int data_len; __u16 mac_len; __u16 queue_mapping; /* 协议相关 */ __be16 protocol; __u16 transport_header; __u16 network_header; __u16 mac_header; /* 数据区域 */ sk_buff_data_t tail; sk_buff_data_t end; unsigned char *head; unsigned char *data; /* 其他控制信息 */ atomic_t users; unsigned int truesize; unsigned char hash; __u8 local_df:1; __u8 cloned:1; __u8 nohdr:1; /* ... */ }; ``` ### 2. 主要成员说明 1. **链表指针** - next/prev: 用于将多个sk_buff连接成链表 - sk: 指向关联的socket结构 2. **设备信息** - dev: 数据包的收发设备 - len: 数据包总长度 - data_len: 非线性数据长度 3. **协议头指针** - transport_header: 传输层头部位置 - network_header: 网络层头部位置 - mac_header: 链路层头部位置 4. **数据区域指针** - head: 缓冲区起始位置 - data: 实际数据起始位置 - tail: 实际数据结束位置 - end: 缓冲区结束位置 ## 内存布局 ### 1. 线性数据区 ```text +-------------------+ | head room | +-------------------+ | MAC header | +-------------------+ | Network header | +-------------------+ | Transport header | +-------------------+ | Data | +-------------------+ | tail room | +-------------------+ ``` ### 2. 非线性数据区(分片) ```c struct skb_shared_info { atomic_t dataref; unsigned short nr_frags; unsigned short gso_size; unsigned short gso_segs; unsigned short gso_type; struct sk_buff *frag_list; skb_frag_t frags[MAX_SKB_FRAGS]; }; ``` ## 核心操作 ### 1. 分配与释放 ```c /* 分配sk_buff */ struct sk_buff *alloc_skb(unsigned int size, gfp_t priority) { struct sk_buff *skb; u8 *data; /* 分配sk_buff结构体 */ skb = kmem_cache_alloc(skbuff_head_cache, priority & ~__GFP_DMA); if (!skb) return NULL; /* 分配数据区域 */ size = SKB_DATA_ALIGN(size); data = kmalloc(size + sizeof(struct skb_shared_info), priority); if (!data) goto nodata; /* 初始化 */ memset(skb, 0, offsetof(struct sk_buff, tail)); skb->truesize = size + sizeof(struct sk_buff); atomic_set(&skb->users, 1); skb->head = data; skb->data = data; skb_reset_tail_pointer(skb); skb->end = skb->tail + size; /* ... */ return skb; nodata: kmem_cache_free(skbuff_head_cache, skb); return NULL; } /* 释放sk_buff */ void kfree_skb(struct sk_buff *skb) { if (unlikely(!skb)) return; if (likely(!atomic_dec_and_test(&skb->users))) return; /* 释放数据区域 */ skb_release_data(skb); /* 释放sk_buff结构体 */ kmem_cache_free(skbuff_head_cache, skb); } ``` ### 2. 数据操作 ```c /* 添加数据到头部 */ unsigned char *skb_push(struct sk_buff *skb, unsigned int len) { skb->data -= len; skb->len += len; return skb->data; } /* 添加数据到尾部 */ unsigned char *skb_put(struct sk_buff *skb, unsigned int len) { unsigned char *tmp = skb_tail_pointer(skb); skb->tail += len; skb->len += len; return tmp; } /* 移除头部数据 */ unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) { skb->len -= len; return skb->data += len; } ``` ### 3. 克隆与复制 ```c /* 克隆sk_buff */ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t priority) { struct sk_buff *n; n = kmem_cache_alloc(skbuff_head_cache, priority); if (!n) return NULL; /* 复制sk_buff结构 */ memcpy(n, skb, offsetof(struct sk_buff, tail)); /* 共享数据区域 */ n->cloned = 1; atomic_inc(&skb_shinfo(skb)->dataref); /* ... */ return n; } /* 复制sk_buff */ struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t priority) { struct sk_buff *n; unsigned int size; /* 分配新的sk_buff */ n = alloc_skb(skb->len, priority); if (!n) return NULL; /* 复制数据 */ size = skb->len - skb->data_len; memcpy(n->data, skb->data, size); /* 复制分片数据 */ if (skb_copy_bits(skb, size, skb_put(n, skb->data_len), skb->data_len)) goto fault; return n; fault: kfree_skb(n); return NULL; } ``` ## 使用场景 ### 1. 数据包接收 ```c static int my_net_rx(struct sk_buff *skb) { /* 获取协议类型 */ __be16 protocol = eth_type_trans(skb, dev); skb->protocol = protocol; /* 移除以太网头部 */ skb_pull(skb, ETH_HLEN); /* 传递给上层协议 */ return netif_rx(skb); } ``` ### 2. 数据包发送 ```c static int my_net_tx(struct sk_buff *skb) { /* 预留以太网头部空间 */ skb_push(skb, ETH_HLEN); /* 填充以太网头部 */ struct ethhdr *eth = (struct ethhdr *)skb->data; memcpy(eth->h_dest, dest_mac, ETH_ALEN); memcpy(eth->h_source, src_mac, ETH_ALEN); eth->h_proto = protocol; /* 发送数据包 */ return dev_queue_xmit(skb); } ``` ## 性能优化 ### 1. 零拷贝技术 1. **页面共享** - 使用页面映射避免数据复制 - 支持sendfile等零拷贝操作 2. **分散/聚集IO** - 使用分片支持大数据包 - 减少内存拷贝次数 ### 2. 内存对齐 ```c /* 数据对齐宏 */ #define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES - 1)) & \ ~(SMP_CACHE_BYTES - 1)) ``` ### 3. 缓存优化 1. **预留空间** - headroom和tailroom预留 - 避免频繁的内存重新分配 2. **缓存行对齐** - 结构体成员排序优化 - 减少伪共享 ## 调试技巧 ### 1. 内核调试 ```c /* 打印sk_buff信息 */ void print_skb_info(struct sk_buff *skb) { printk(KERN_INFO "SKB info:\n"); printk(KERN_INFO " len: %u\n", skb->len); printk(KERN_INFO " protocol: 0x%04x\n", ntohs(skb->protocol)); printk(KERN_INFO " dev: %s\n", skb->dev ? skb->dev->name : "<null>"); } ``` ### 2. 网络工具 ```bash # 使用tcpdump查看数据包 tcpdump -i eth0 -vv # 使用netstat查看统计信息 netstat -s ``` ## 常见问题 ### 1. 内存泄漏 - 确保正确调用kfree_skb - 注意引用计数管理 - 处理错误情况下的清理 ### 2. 并发访问 - 使用原子操作 - 正确处理克隆和共享 - 避免竞态条件 ### 3. 性能问题 - 减少不必要的拷贝 - 合理使用预留空间 - 优化内存分配策略 ## 总结 sk_buff结构是Linux网络协议栈的核心数据结构,它通过灵活的设计支持了高效的数据包处理。理解sk_buff的结构和操作对于网络驱动开发和协议栈优化至关重要。合理使用sk_buff提供的功能可以实现高性能的网络数据处理。 ## 参考资源 1. Linux内核源码: include/linux/skbuff.h 2. [Linux网络数据包的接收过程](https://blog.csdn.net/dog250/article/details/50528280) 3. [Understanding Linux Network Internals](http://shop.oreilly.com/product/9780596002558.do)