Preface

Linux内核对网络驱动程序使用统一的接口,并且对于网络设备采用面向对象的思想设计。

Linux内核采用分层结构处理网络数据包。分层结构与网络协议的结构匹配,既能简化数据包处理流程,又便于扩展和维护。

一、内核网络结构

在Linux内核中,对网络部分按照网络协议层、网络设备层、设备驱动功能层和网络媒介层的分层体系设计。

网络驱动功能层主要通过网络驱动程序实现。

在Linux内核,所有的网络设备都被抽象为一个接口处理,该接口提供了所有的网络操作。

net_device结构表示网络设备在内核中的情况,也就是网络设备接口。网络设备接口既包括软件虚拟的网络设备接口,如环路设备,也包括了网络硬件设备,如以太网卡。

Linux内核有一个dev_base的全局指针,指向一个设备链表,包括了系统内的所有网络设备。该设备链表每个节点是一个网络设备。

在net_device结构中提供了许多供系统访问和协议层调用的设备方法,包括初始化、打开关闭设备、数据包发送和接收等。

内核对网络数据包的处理都是基于sk_buff结构的,该结构是内核网络部分最重要的数据结构。

网络协议栈中各层协议都可以通过对该结构的操作实现本层协议数据的添加或者删除。使用sk_buff结构避免了网络协议栈各层来回复制数据导致的效率低下。

sk_buff结构可以分为两个部分,一部分是存储数据包缓存,在图中表示为PackertData,另一部分是由一组用于内核管理的指针组成。

sk_buff管理的指针最主要的是下面4个:

    • head指向数据缓冲(PackertData)的内核首地址;

    • data指向当前数据包的首地址;

    • tail指向当前数据包的尾地址;

    • end 指向数据缓冲的内核尾地址。

数据包的大小在内核网络协议栈的处理过程中会发生改变,因此data和tail指针也会不断变化,而head和tail指针是不会发生改变的。

对于一个TCP数据包为例,sk_buff还提供了几个指针直接指向各层协议头。mac指针指向数据的mac头;nh指针指向网络协议头,一般是IP协议头;h指向传输层协议头,在本例中是TCP协议头。

对各层设置指针的是方便了协议栈对数据包的处理。

Linux内核中网络设备最重要的数据结构就是net_device结构了,它是网络驱动程序最重要的部分。

net_device结构保存在include/linux/netdevices.h头文件,理解该结构对理解网络设备驱动有很大帮助。

内核中所有网络设备的信息和操作都在net_device设备中,无论是注册网络设备,还是设置网络设备参数,都用到该结构。

下面是主要数据成员。

    • 设备名称

    • 总线参数

    • 协议参数

    • 链接层变量

    • 接口标志

四、数据包接收流程

在Linux内核中,一个网络数据包从网卡接收到用户空间需要经过链路层、传输层和socket的处理,最终到达用户空间。

以DM9000网卡为例,当网卡收到数据包以后,调用中断处理函数 dm9000_interrupt(),该函数检查中断处理类型,如果是接收数据包中断,则调用 dm9000_rx()函数接收数据包到内核空间。

dm9000_rx()函数收到数据包完成后,内核会继续调用 netif_rx()函数,函数的作用是把网卡接收到数据提交给协议栈处理。

协议栈使用 net_rx_action()函数处理接收数据包队列,该函数处理数据包后如果是 IP数据包则提交给ip_recv()函数处理。ip_recv()函数主要是检查一个数据包IP头的合法性,检查通过后交给 ip_local_deliver()和 ip_local_deliver_finish()函数处理,之所以分开处理是因为内核中有防火墙相关的代码需要动态加载到此处。

IP头处理完毕后,以UDP数据包为例将交由 udp_recv()函数处理,与 ip_recv()函数类亿,该函数检查 UDP头的合法性,然后交给 udp_queue_recv()函数处理,最后提交给 sock_queue_recv()函数处理。

数据包进入 socket部分的第一个函数是 skb_recv_datagram(),该函数从内核的 socket队列取出数据包,交给 socket部分的 udp_recvmsg()函数,该函数负责处理UDP的数据,sock_recvmsg()处理提交给 sock_read()函数。

sock_read()函数读取接收到的数据缓冲,把数据返回给 sys_read()系统调用。sys_read()函数调用最终把数据复制到用户空间,供用户使得。

五、数据包发送流程

以UDP数据包发送流程为例,在DM9000网卡上如何发送一个数据包。

当用户空间的应用程序通过 socket函数 sento()发送一个UDP数据后,会调用内核空间的 sock_writev()函数,然后通过 sock_sendmsg()函数处理。sock_sendmsg()函数调用 inet_sendmsg()函数处理,inet_sendmsg()函数会把要发送的数据交给传输层的 udp_sendmsg()函数处理。

udp_sendmsg()函数在数据前加入UDP头,然后把数据交给 ip_build_xmit()函数处理,该函数根据 socket提供的目的 IP和端口信息构造IP头,然后调用 output_maybe_reroute()函数处理。out_maybe_reroute()函数检查数据包是否需要经过路由,最后交给 ip_output()函数写入到发送队列,写入完成后由 ip_finish_output()函数处理后续工作。

链路层的 dev_queue_xmit()函数处理发送队列,调用 DM9000网卡的发送数据包函数 dm9000_xmit()发送数据包,发送完毕后,调用 dm9000_xmit_done函数处理发送结果。

版权声明:本文为博主原创文章,未经博主允许不得转载。

Linux 网络设备驱动开发(一) —— linux内核网络分层结构的更多相关文章

  1. 【驱动】网卡驱动·linux内核网络分层结构

    Preface   Linux内核对网络驱动程序使用统一的接口,并且对于网络设备采用面向对象的思想设计. Linux内核采用分层结构处理网络数据包.分层结构与网络协议的结构匹配,既能简化数据包处理流程 ...

  2. [转]linux内核网络分层结构

    Preface   Linux内核对网络驱动程序使用统一的接口,并且对于网络设备采用面向对象的思想设计. Linux内核采用分层结构处理网络数据包.分层结构与网络协议的结构匹配,既能简化数据包处理流程 ...

  3. Linux设备驱动开发环境的搭建(转)

    经过两周的摸索,终于对Linux设备驱动开发有了个初步的认识,下面对Linux设备驱动开发环境的搭建做个小结,以方便自己以后查询,同时也能给同道的初学者一点帮助. 刚接触Linux设备驱动时,初学者往 ...

  4. 转:Linux设备驱动开发(1):内核基础概念

    一.linux设备驱动的作用 内核:用于管理软硬件资源,并提供运行环境.如分配4G虚拟空间等. linux设备驱动:是连接硬件和内核之间的桥梁. linux系统按个人理解可按下划分: 应用层:包括PO ...

  5. 《Linux设备驱动开发具体解释(第3版)》(即《Linux设备驱动开发具体解释:基于最新的Linux 4.0内核》)网购链接

    <Linux设备驱动开发具体解释:基于最新的Linux 4.0内核> china-pub   spm=a1z10.3-b.w4011-10017777404.30.kvceXB&i ...

  6. 《Linux设备驱动开发详解(第2版)》配套视频登录51cto教育频道

    http://edu.51cto.com/course/course_id-379-page-1.html http://edu.51cto.com/course/course_id-379-page ...

  7. Linux网络设备驱动架构

    Linux网络设备驱动程序体系结构分为四层:网络协议接口层.网络设备接口层.提供实际功能的设备驱动层以及网络设备与媒介层. (1)网络协议接口层向网络层协议提供统一的数据包收发接口,不论上层协议是AR ...

  8. Linux网络设备驱动架構學習(三)

    Linux网络设备驱动架構學習(三) 接下來會從以下幾個方面介紹網絡設備驅動的編寫流程: 1.網絡設備的註冊與註銷 2.網絡設備的初始化 3.網絡設備的打開與釋放 4.網絡數據發送流程 5.網絡數據接 ...

  9. 《Linux设备驱动开发具体解释(第3版)》进展同步更新

    本博实时更新<Linux设备驱动开发具体解释(第3版)>的最新进展. 2015.2.26 差点儿完毕初稿. 本书已经rebase到开发中的Linux 4.0内核,案例多数基于多核CORTE ...

随机推荐

  1. MVC开发人员必备的五大工具

    1. Chirpy Zippy 下载地址:http://chirpy.codeplex.com/ 过去,在将JavaScript脚本和CSS文件部署到Web服务器之 前,我习惯使用压缩工具进行压缩再部 ...

  2. eclipse 创建 maven 项目时如何修改 web 的版本和 jdk 的版本

    eclipse 创建 maven 项目时如何修改 web 的版本和 jdk 的版本 在使用 eclipse 创建 maven 项目的时候,默认的 web.xml 的版本时 2.3,默认 jre 的版本 ...

  3. java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES) 解决办法

    一.背景 在Spark中,将DStream写入到MySQL出现错误:java.sql.SQLException: Access denied for user 'root'@'localhost' ( ...

  4. Redis Cluster集群的搭建与实践

    Redis Cluster集群 一.redis-cluster设计 Redis集群搭建的方式有多种,例如使用zookeeper等,但从redis 3.0之后版本支持redis-cluster集群,Re ...

  5. checkbox 更改样式

    html: <div class="wrap"> <p>1. 勾选</p> <input type="checkbox" ...

  6. Java反序列化漏洞之殇

    ref:https://xz.aliyun.com/t/2043 小结: 3.2.2版本之前的Apache-CommonsCollections存在该漏洞(不只该包)1.漏洞触发场景 在java编写的 ...

  7. Python开发基础-Day25-28FTP项目(待补充)

    optparse C:\Users\Mr.chai>python C:/Users/Mr.chai/Desktop/PythonProject/DAY/day27/LuffyFTP/client ...

  8. Python正则模块

    re模块 import re # match # 从头开始匹配, 只匹配一次,就结束 a = re.match('\d+', '54:58天5488:8451') # 默认就是0个群组 print(a ...

  9. 【HDU 6021】 MG loves string (枚举+容斥原理)

    MG loves string  Accepts: 30  Submissions: 67  Time Limit: 2000/1000 MS (Java/Others)  Memory Limit: ...

  10. 【BZOJ 2039】 2039: [2009国家集训队]employ人员雇佣 (最小割)

    2039: [2009国家集训队]employ人员雇佣 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 1511  Solved: 728 Descri ...