Chinaunix首页 | 论坛 | 博客
  • 博客访问: 338897
  • 博文数量: 73
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 421
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-03 15:18
个人简介

做笔记用,多为转载。

文章分类

全部博文(73)

文章存档

2016年(2)

2015年(29)

2014年(19)

2013年(23)

我的朋友

分类: LINUX

2015-05-12 21:20:40

linux网络设备驱动结构

linux网络设备驱动可以划分为4层,分别是网络协议接口层、网络设备接口层、设备驱动功能层、网络设备与媒介层。

 

网络协议接口层

网络协议接口层的最主要功能是给上层协议提供透明的数据包发送和接收接口。dev_queue_xmit(struct sk_buff *skb) 发送数据, netif_rx(struct sk_buff *skb) 接收数据。

    sk_buff是非常重要的结构体,叫做"套接字缓冲区",各层之间的数据传输都依赖该结构体。
    1、在发送数据包时,各层在sk_buff中添加不同的协议头直至交给网络设备发送;
    2、在从网络媒介上接收数据包后,需将其转换为sk_buff并传递给上层,各层剥去相应的协议头直至交给用户;

    sk_buff结构体内容:
    1、协议头    transport_header(传输层协议头),network_header(网络层协议头),mac_header(数据链路层协议头)。
    2、数据缓冲区指针
    head :缓冲区起始地址, sk_buff 一旦创建, head 数据就固定了。
    data :当前协议层的有效数据起始地址
    tail : 当前协议层有效数据的结尾地址,和data 对应
    end :缓冲区的结尾地址, sk_buff 一旦创建, end 数据就固定了。
    

    3、长度信息
    len: 数据包有效数据长度,包括协议头和负载( Payload
    data_len:记录分片的数据长度 , 数据包的有效数据是分成几片存在不同的内存空间中,每片空间最大是一页。
    truesize :缓冲区的整体长度,即: sizeof(struct sk_buff)+ (传入 alloc_sdb() dev_alloc_skb() 函数的长度)一般分配一个sk_buff长度和一个数据缓冲区。


    sk_buff操作
    1、分配
    struct sk_buff   *alloc_skb(unsigned int len,int priority); 分配一个套接字缓冲区( sk_buff )和一个数据缓冲区,参数 len 为数据缓冲区的空间大小。 16 字节对齐, priority 是内存分配的优先级。
    struct sk_buff   *dev_alloc_skb(unsigned int len);
    用这个函数优先级就确定了 --FGP_ATOMIC: 代表分配过程中不能被中断。 会调用 alloc_skb() 函数,并保存 skb->head 和 sdk_data 之间的 16 个字节。 分配完成后 , skb_buff  的 data 、 tail 指针都指向存储空间的起始地址 head, 而 len 的大小是 0 。

    2、释放
    就是释放 alloc_skb() 分配的套接字缓冲区,和数据缓冲区。
    linux 专用:
    void kree_skb(struct sk_buff   *skb) ;
    网络设备驱动程序用:
    非中断上下文专用: void dev_kree_skb(struct  sk_buff  *skb);
    中断上下文转用: void dev_kree_skb_irq(strcut sk_buff   *skb);
    中断非中断上下文都可用: void dev_kree_skb_any(struct sk_buff  *skb);

    3、指针移动
    (1)put 操作:
    往数据缓冲区尾部 添加可以存储网络数据包的空间。
    unsigned char *skb_put (struct sk_buff  *skb , unsigned int len);          // 会检测放入的数据
    unsigned char *__skb_put ( 同上 ) ;   // 不检查
    上述函数使 tail 指针下移,增加 sk_buff 中的 len 值,并返回 skb_tail 的值。 
    (2)push 操作:
    往数据缓冲区头部 增加一段可以存储网络数据包的空间。主要用于在数据包发送时添加头部。
    unsigned char *skb_push (struct sk_buff  *skb , unsigned int len);       // 会检测放入的数据
    unsigned char *__skb_push ( 同上 ) ;  // 不检查
    会使 data 指针上移,也增加 len 的值。 
    (3)pull 操作:
    用于下层协议向上层协议移交数据包,使 data 指针指向上一层协议的协议头。
    unsigned char *skb_pull (struct sk_buff  *skb , unsigned int len);
    会将 data 指针下移,并减小 skb 的 len 值。 
    (4)reserve 操作:
    主要用于在存储空间的头部预留 len 长度的空隙。
    void skb_reserve (struct sk_buff  *skb , unsigned int len);
    会使 data 指针和 tail 指针同时下移。

    举例以太网卡收到一个UDP数据包后,linux从底层到应用层处理的过程
     
    1、驱动创建一个sk_buff结构体和数据缓冲区,收到的数据复制到data指向的空间,并将skb->mac_header指向data(链路层以太网头),此时有效数据的起始位置是链路层以太网头。
    2、数据链路层调用skb_pull 传到网络层之后,以太网协议头被剥掉了, skb->data 指向下移到 IP 头了, len 也减掉链路层头部那个长度 skb->network_header指向 data ,即 IP 头部。
    3、网络层调用skb_pull pull 传到传输层,剥掉 IP 头, data 指针继续向下移, len 长度再减掉 ip 头长度, skb->transport_header 指向 UDP 头部。
    4、应用程序调用 recv() 接收数据时,从 skb->data+sizeof(struct udphdr) 的位置开始复制到应用层缓冲区,所以 ,UDP 头得以幸存,没有被剥掉


网络设备接口层
    网络设备接口层的主要作用是将具体的网络设备抽象成一个net_device结构体,实现多种mac硬件在软件层上的统一。
设备驱动功能层
    该层包含对具体以太网设备的操作函数,用于填充net_device结构体。例如814x的在cpsw.c中。
网络设备与媒介层
    该层主要用来操作实际的设备的物理配置和相关寄存器,814x中也在cpsw.c中。

阅读(1322) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~