写在前面
刚刚加入Linux内核底层通信开发的项目组,之前没有任何的相关内容的学习工作经验,从今天
2017.9.6
开始记录下从基础知识学习开始的全过程中自己总结的知识要点,希望我再次回来翻看的时候已经成为一个Linux内核大神了 ╰(°▽°)╯
开发的硬件环境及版本
这篇blog的目的在于分阶段地记录下在使用Lgson3.10开发板基础上对Intel千兆网卡82574的底层驱动的阅读和修改的全过程。
Linux版本号为 3.10.107。
嵌入式以太网基础知识
以太网技术及其嵌入式应用
如今以太网一词更多的被用来指各种采用CSMA/CD技术的局域网。IEEE 802.3规范是基于最初的以太网技术于1980年制定的。其中在底层,以太网数据是划分为帧的形式进行传输的。
以太网帧的基本结构
- 同步位: 由0和1间隔组成,可以通过目标站做好接收准备。
- 目标地址:表示发送帧的工作站的地点,占6字节。
- 源地址: 表示接受帧的地址,也占6字节。
- 类型:占2字节,指定接收数据的高层协议。
- 数据:不能超过1500字节,不能低于46字节。如果过小,则会自动填充数据段,以确保不低于46字节。
- 帧校验序列(FCS):该序列包含长度为4字节的CRC,以确定数据帧是否被损坏。
以太网采用广播机制,所有与网络连接的工作站都可以看到网络上传递的数据,并通过查看包含在帧中的目标地址,确定是接受还是丢弃。
嵌入式系统中所主要体现的网络分层结构
Linux系统网络所实现的分层结构中,上层被称为用户空间,下层我们所接触的部分称为内核空间,其内部划分如下:
- 协议层: 包括IP层、INET Socket层以及BSD Socket层,其中:
- BSD Socket层:在应用层和协议层之间的BSD Socket层的应用程序接口以4.4BSD为模板,原因是流行性和可移植的特性。
- INET Socket层:比IP协议的实现层次要高,其作用是 实现对IP的分组排序,以及控制网络系统效率等功能。该层根据建立连接的类型分成基于IP协议的TCP和UDP两种传输类型,在IP层实现Internet协议的代码。
- IP层:这层不用多说,而在这层以下包括各种型号各异的网络设备,不仅包括物理设备,也包括用各种软件实现的类似于Loopback的虚拟网络设备。
设备驱动层:该层实现了硬件驱动及数据包的发送和接收的组织工作。
主要涉及的基本的网络协议
-
ARP (Address Resolution Protocol) 地址解析协议
因为网络层与链路层使用了不同的地址来标识主机,因此需要实现这两者之间的转换。源主机发送一份包含目的主机的IP地址的ARP请求数据帧给网络上的每一个主机,称作ARP广播,之后接收一份包含目的主机的MAC地址的应答,从而确定后续发送的数据帧中的目的地址的值。
为了加快ARP协议解析数据的速度,每一台主机上都有一个ARP高速缓存,以存放最近的IP地址到硬件地址之间的映射记录。 -
IP (Internet Protocol) 网际协议
TCP/IP协议族中最为核心的协议,其他的协议可以利用它来传输数据,传输的单位是数据包,每个数据包都有一个IP数据头,其中包括源地址和目的地址,一个数据校验和,以及其他各种会可以在课本上查阅得到的信息。最长65535字节,其中32bit的报头、32bit的源IP地址和32bit的目的IP地址。它所提供的服务具有以下特点:
-
不可靠
如果数据包不能成功到达目的地则丢弃,并发送消息报告。 -
无连接
IP并不维护任何关于后续数据包的状态信息,每个数据包是相互独立的,数据包之间并不是按顺序进行接收的。 -
高效灵活
正是由于不可靠和无连接,使得IP协议构成了网络分层结构中细腰 特点的不可替代的那个最细的部分,其高效灵活的传输至今难以替代。
-
不可靠
-
TCP (Transfer Control Protocol) 传输控制协议
基于连接的协议,为人所熟知,不赘述了。值得注意的是,当应用程序使用TCP/IP通信时,它们不仅要指明目标机的IP地址,还要指明应用程序使用的端口地址。端口地址可以唯一地表示一个应用程序,标准的网络应用程序使用标准的端口地址。已经登记的端口地址可以在
/etc/services
中查看。 -
UDP (User Datagram Protocol) 用户数据包协议
一种无连接、不可靠的传输层协议,其可靠性由应用层来决定。因为协议开销小,与TCP相比,UDP更适合用于低端的嵌入式领域之中。
使用UDP协议的主要场合有:- 网络管理 SNMP
- 域名解析 DNS
- 简单文件传输协议 TFTP 等
UDP具有TCP所望尘莫及的速度优势。UDP将安全和排序等功能移交给上层的应用来完成,极大地降低了执行的时间,使得速度得到了保证。然而经常性地会牺牲一定的可靠性(例如画面质量)。
网络设备的驱动设计
在嵌入式系统中添加以太网接口,主要有以下两种方式
- 采用带有以太网接口的嵌入式处理器 这种方法要求嵌入式处理器所采用的是通用的网络接口,通过内部总线的方式实现处理器和网络数据交换。
- 采用嵌入式处理器加网卡芯片结构 对处理器的接口没有特殊的要求,只需要将以太网芯片连接至嵌入式处理器的总线。通用性强,然而交换数据是走外部总线。
驱动程序的结构浅析
首先,网络设备通常是一个物理设备,然而,软件模拟出的虚拟网络设备也可以作为网络设备,例如回送设备 Loopback 。第一步,在内核启动时,系统先通过网络设备的驱动程序来获取已经存在的网络设备,想要从头开始纵向地阅读这个部分我们首先要做的就是找到这一步所使用的网络设备接口的登记表的位置。(这里先留个坑等回头找着了回来填)。
不管底层的设备驱动程序是什么,它会返回一个状态来显示它是否定位到了所驱动的控制器。否则由管理列表指针指向的设备数据结构就被删除。在Linux中,这个统一的接口就是数据结构 device 。 每一个设备的方法被调用时的第一个参数都是这个设备对象本身。这样,这个方法就可以存取自身的数据,类似于面向对象程序设计时的this引用。
网络设备的驱动程序体系结构如下:
- 设备媒介层 网络物理设备和媒介
- 设备驱动功能层 初始化,其中
dev_hard_start_xmit()
这个位置在 net\core\dev.c 中的函数负责向硬件发送数据;mydevice_interrupt()
从硬件接收数据。- 网络设备接口层 struct device数据结构的变量和方法
- 网络协议接口层
dev_queue_xmit()
函数向下层传递数据,同时netif_rx()
向上层传送数据。
以上就是嵌入式以太网的大致基础知识,从下篇开始一点一点的详细寻找定义并尝试自己进行解释。