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协议头。

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


net_device结构

   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函数处理发送结果。

本文转自http://infohacker.blog.51cto.com/6751239/1221140

[转]linux内核网络分层结构的更多相关文章

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

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

  2. Linux 网络设备驱动开发(一) —— linux内核网络分层结构

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

  3. Linux内核--网络栈实现分析(十一)--驱动程序层(下)

    本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7555870 更多请查看专栏,地 ...

  4. Linux内核--网络栈实现分析(七)--数据包的传递过程(下)

    本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7545855 更多请查看专栏,地 ...

  5. Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上)

    本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7497260 更多请看专栏,地址 ...

  6. Linux内核--网络栈实现分析(一)--网络栈初始化

    本文分析基于内核Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7488828 更多请看专栏, ...

  7. Linux内核--网络栈实现分析(二)--数据包的传递过程--转

    转载地址http://blog.csdn.net/yming0221/article/details/7492423 作者:闫明 本文分析基于Linux Kernel 1.2.13 注:标题中的”(上 ...

  8. Linux内核--网络栈实现分析(一)--网络栈初始化--转

    转载地址 http://blog.csdn.net/yming0221/article/details/7488828 作者:闫明 本文分析基于内核Linux Kernel 1.2.13 以后的系列博 ...

  9. Linux内核网络数据包处理流程

    Linux内核网络数据包处理流程 from kernel-4.9: 0. Linux内核网络数据包处理流程 - 网络硬件 网卡工作在物理层和数据链路层,主要由PHY/MAC芯片.Tx/Rx FIFO. ...

随机推荐

  1. Android4.2.2NDK和源代码开发jni的异同

    C/C++开发,在NDK和源代码中输出Log信息的方法! NDK: 1.包括头文件 #include <android/log.h> 2.Android.mk中包括库 LOCAL_LDLI ...

  2. js 中时间格式化的几种方法

    1.项目中时间返回值,很过时候为毫秒值,我们需要转换成 能够看懂的时间的格式: 例如: yyyy-MM-dd HH:mm:ss 2.处理方法(处理方法有多种,可以传值到前端处理,也可以后台可以好之后再 ...

  3. Android网络请求之OkHttp框架

    首先声明权限 <uses-permission android:name="android.permission.INTERNET"/> 在build.gradle中加 ...

  4. UEFI+GPT引导基础篇 :什么是GPT,什么是UEFI?

    GUID Partition Table (GPT) is a standard for the layout of the partition table on a physical storage ...

  5. Visual Studio 2013键盘码农常用快捷键

    声明及广告 所有功能针对C#开发配置而写,面向人群是喜欢键盘操作而非鼠标操作的开发者.部分功能可能由插件提供,我会尽可能标注出相应的插件名称.为行文方便,所有快捷键以大写形式表示.太常用的快捷键,如C ...

  6. XSS第四节,XSS攻击实例(一)

    在开始实例的讲解之前,先看一下XSS的危害情况,第一张图中说明和XSS相关的CVE漏洞有7417个(http://web.nvd.nist.gov/view/vuln/search-results?q ...

  7. 简单MapReduce思维导图

  8. 局域网Cesium离线影像及瓦片影像地图加载【转】

    http://www.mamicode.com/info-detail-2161992.html 1.Cesium简介 优点: cesium展示地图数据效果比较好,解析2D地图各种不同服务类型的数据源 ...

  9. CentOS开启和关闭防火墙

    CentOS Linux开启和关闭防火墙命令有两种,一种是临时的,重启即复原:另外一种是永久性的,重启不会复原.   1) 临时生效,重启后复原 开启: service iptables start ...

  10. 日程管理app

    背景: 普通的笔记本显然具有保存占用较大空间的弊端.而笔记类app又借助于虚拟按键输入,便利度稍逊.假设使用电脑,又产生了较大空间的弊端. 手段: 成熟的书写识别技术 方法: 一.专有的划分有制定格子 ...