Chinaunix首页 | 论坛 | 博客
  • 博客访问: 81802
  • 博文数量: 21
  • 博客积分: 1400
  • 博客等级: 上尉
  • 技术积分: 170
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-29 10:03
文章分类
文章存档

2010年(21)

我的朋友

分类: LINUX

2010-07-29 11:00:38

24.8  接收过程的实现

接收函数一般由中断控制程序调用,负责把网络设备接收到的数据以一定格式提交给内核中的网络层模块。在具体介绍接收函数前先简单介绍一下sk_buff结构。

24.8.1  sk_buff结构

sk_buff是Linux网络协议栈中一个重要数据结构,网络协议栈中的各层协议都可以通过对它的操作实现本层协议数据的添加或者数据提取,这种机制避免了协议数据单元在不同的协议层间被来回复制情况的发生,提高了执行效率。内核在各协议层都提供一系列函数对此结构进行操作。如图24-4所示为sk_buff结构的示意图。

sk_buff的数据分成两大部分,一部分是实际在网络中要传输的部分,图中表示为Packet date storage部分,这就是常说的数据区。另一部分是用于内核进行管理的部分。在此着重介绍要用到的几个域段。其中有四个数据指针指向数据区相应的位置。

unsigned char *head:指向被分配的内存空间的首地址;

unsigned char *data:指向当前数据包的首地址;

unsigned char *tail:指向当前数据包的末地址;

unsigned char *end:指向被分配的内存空间的末地址;

 
(点击查看大图)图24-4  sk_buff结构

unsigned long len:当前数据包的大小。len=skb->tail - skb->data;

unsigned long truesize:分配到的内存空间大小。len=skb->end - skb->head;

struct net_device *dev:接收或者发送该数据包的网络设备;

unsigned short:protocol给数据包使用的网络层协议。

由于数据包的大小会随着自己在不同协议层间的传送而不断地变化,故data和tail指针也将会不断地改变,即依赖于sk_buff当前所在的协议层;head和end指针则在内存空间分配后就固定不变。

对sk_buff缓冲区的操作,核心提供了一个比较完整的函数界面,下面将列出用得最多的几个函数并作分析说明。

struct sk_buff*alloc_skb (unsigned int len, int priority);
struct sk_buff*dev_alloc_skb (unsigned int len);
申请一个sk_buff缓冲区。alloc_skb函数分配一个缓冲区并将skb->data和skb->tail初始化为skb->head;dev_alloc_skb函数是alloc_skb函数的一个快捷方式,它用priority=GFP_ATOMIC调用alloc_skb并在skb->data和skb->head之间保留16字节的空间。这16字节也用来填写硬件头(hardware header)。
void kfree_skb (struct sk_buff*skb, int rw);
void dev_kfree_skb (struct sk_buff*skb, int rw);
释放一个sk_buff缓冲区。kfree_skb()供核心内部调用,驱动程序应该用dev_kfree_skb(),因为它能正确处理缓冲区加锁。参数rw可用FREE_READ或FREE_WRITE。用于发送的缓冲区应该用FREE_WRITE,用于接收的则用FREE_READ。
unsigned char *skb_put (struct sk_buff*skb, int len);
当有数据要加到缓冲区的尾部时,用于增加skb->tail和skb->len。返回值是修改之前的skb->tail指针。
unsigned char *skb_push (struct sk_buff*skb, int len);
当有数据要加到缓冲区的首部时,用于减少skb->data及增大skb->len。返回值是修改之后的skb->data。
int skb_tailroom (struct sk_buff*skb);
该函数返回在sk_buff中可用于put的空间大小(尾部空余空间)。如果缓冲区被正确分配到空间,驱动程序通常不需要检查缓冲区中剩余空间的大小。由于驱动程序在申请空间之前可得到数据包的大小,故只有严重出错的驱动程序才会put太多的数据到缓冲区中。
int skb_headroom (struct sk_buff*skb);
类似于skb_tailroom(),该函数返回可用的push的空间大小,即首部空余空间。
void skb_reserve (struct sk_buff*skb, int len);
该函数既增加skb->data又增加skb->tail,即在首部留出len大小的空间。在填充缓冲区之前,可用该函数保留一部分首部空间。许多以太网卡在首部保留2字节空间,这样在14字节的以太网头的后面,IP头就能以16字节对齐了。
unsigned char *skb_pull (struct sk_buff*skb, int len);
从数据包的头部剔除数据。它减少skb->len并增加skb->data。以太网的头就是这样从接收到的数据包中被剔除的。
void skb_trim(struct sk_buff*skb, int len)
从数据包的尾部剔除数据。它将skb->len设为len,并改变skb->tail。
阅读(1522) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~