热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

骨灰级老鸟的技术放送:网卡驱动编写

文章标题:骨灰级老鸟的技术放送:网卡驱动编写。Linux是中国IT实验室的一个技术频道。包含桌面应用,Linux系统管理,内核研究,嵌入式系统和开源等一些基本分类

  
  概述
  一.linux系统设备驱动程序概述
  1.1 linux设备驱动程序分类
  linux设备驱动程序在Linux的内核源代码中占有很大的比例,源代码的长度日益增加,主要是驱动程序的增加。在Linux内核的不断升级过程中,驱动程序的结构还是相对稳定。在2.0.xx到2.2.xx的变动里,驱动程序的编写做了一些改变,但是从2.0.xx的驱动到2.2.xx的移植只需做少量的工作。
  linux系统的设备分为字符设备(char device),块设备(block device)和网络设备(network device)三种。字符设备是指存取时没有缓存的设备。块设备的读写都有缓存来支持,并且块设备必须能够随机存取(random access),字符设备则没有这个要求。典型的字符设备包括鼠标,键盘,串行口等。块设备主要包括硬盘软盘设备,CD-ROM等。一个文件系统要安装进入操作系统必须在块设备上。
  
  网络设备在linux里做专门的处理。Linux的网络系统主要是基于BSD unix的socket机制。在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。系统里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持。
  
  1.2 编写驱动程序的一些基本概念
  无论是什么操作系统的驱动程序,都有一些通用的概念。操作系统提供给驱动程序的支持也大致相同。下面简单介绍一下网络设备驱动程序的一些基本要求。
  
  1.2.1 发送和接收
  这是一个网络设备最基本的功能。一块网卡所做的无非就是收发工作。所以驱动程序里要告诉系统你的发送函数在哪里,系统在有数据要发送时就会调用你的发送程序。还有驱动程序由于是直接操纵硬件的,所以网络硬件有数据收到最先能得到这个数据的也就是驱动程序,它负责把这些原始数据进行必要的处理然后送给系统。这里,操作系统必须要提供两个机制,一个是找到驱动程序的发送函数,一个是驱动程序把收到的数据送给系统。
  
  1.2.2 中断
  中断在现代计算机结构中有重要的地位。操作系统必须提供驱动程序响应中断的能力。一般是把一个中断处理程序注册到系统中去。操作系统在硬件中断发生后调用驱动程序的处理程序。linux支持中断的共享,即多个设备共享一个中断。
  
  1.2.3 时钟
  在实现驱动程序时,很多地方会用到时钟。如某些协议里的超时处理,没有中断机制的硬件的轮询等。操作系统应为驱动程序提供定时机制。一般是在预定的时间过了以后回调注册的时钟函数。在网络驱动程序中,如果硬件没有中断功能,定时器可以提供轮询(poll)方式对硬件进行存取。或者是实现某些协议时需要的超时重传等。
  
  --------------------------------------------------------------------------------
  设备驱动
  二.linux系统网络设备驱动程序
  2.1 网络驱动程序的结构
  所有的linux网络驱动程序遵循通用的接口。设计时采用的是面向对象的方法。一个设备就是一个对象(device 结构),它内部有自己的数据和方法。每一个设备的方法被调用时的第一个参数都是这个设备对象本身。这样这个方法就可以存取自身的数据(类似面向对象程序设计时的this引用)。
  一个网络设备最基本的方法有初始化、发送和接收。
  
  ------------------- ---------------------
  |deliver packets | |receive packets queue|
  |(dev_queue_xmit()) | |them(netif_rx()) |
  ------------------- ---------------------
  | | /
  / | |
  -------------------------------------------------------
  | methods and variables(initialize,open,close,hard_xmit,|
  | interrupt handler,config,resources,status...) |
  -------------------------------------------------------
  | | /
  / | |
  ----------------- ----------------------
  |send to hardware | |receivce from hardware|
  ----------------- ----------------------
  | | /
  / | |
  -----------------------------------------------------
  | hardware media |
  -----------------------------------------------------
  
  初始化程序完成硬件的初始化、device中变量的初始化和系统资源的申请。发送程序是在驱动程序的上层协议层有数据要发送时自动调用的。一般驱动程序中不对发送数据进行缓存,而是直接使用硬件的发送功能把数据发送出去。接收数据一般是通过硬件中断来通知的。在中断处理程序里,把硬件帧信息填入一个skbuff结构中,然后调用netif_rx()传递给上层处理。
  
  2.2 网络驱动程序的基本方法
  网络设备做为一个对象,提供一些方法供系统访问。正是这些有统一接口的方法,掩蔽了硬件的具体细节,让系统对各种网络设备的访问都采用统一的形式,做到硬件无关性。
  下面解释最基本的方法。
  
  2.2.1 初始化(initialize)
  驱动程序必须有一个初始化方法。在把驱动程序载入系统的时候会调用这个初始化程序。它做以下几方面的工作。检测设备。在初始化程序里你可以根据硬件的特征检查硬件是否存在,然后决定是否启动这个驱动程序。配置和初始化硬件。在初始化程序里你可以完成对硬件资源的配置,比如即插即用的硬件就可以在这个时候进行配置(linux内核对PnP功能没有很好的支持,可以在驱动程序里完成这个功能)。配置或协商好硬件占用的资源以后,就可以向系统申请这些资源。有些资源是可以和别的设备共享的,如中断。有些是不能共享的,如IO、DMA。接下来你要初始化device结构中的变量。最后,你可以让硬件正式开始工作。
  
  2.2.2 打开(open)
  open这个方法在网络设备驱动程序里是网络设备被激活的时候被调用(即设备状态由down-->up)。所以实际上很多在initialize中的工作可以放到这里来做。比如资源的申请,硬件的激活。如果dev->open返回非0(error),则硬件的状态还是down。
  open方法另一个作用是如果驱动程序做为一个模块被装入,则要防止模块卸载时设备处于打开状态。在open方法里要调用MOD_INC_USE_COUNT宏。
  
  2.2.3 关闭(stop)
  close方法做和open相反的工作。可以释放某些资源以减少系统负担。close是在设备状态由up转为down时被调用的。另外如果是做为模块装入的驱动程序,close里应该调用MOD_DEC_USE_COUNT,减少设备被引用的次数,以使驱动程序可以被卸载。
  另外close方法必须返回成功(0==success)。
  
  2.2.4 发送(hard_start_xmit)
  所有的网络设备驱动程序都必须有这个发送方法。在系统调用驱动程序的xmit时,发送的数据放在一个sk_buff结构中。一般的驱动程序把数据传给硬件发出去。也有一些特殊的设备比如loopback把数据组成一个接收数据再回送给系统,或者dummy设备直接丢弃数据。
  如果发送成功,hard_start_xmit方法里释放sk_buff,返回0(发送成功)。如果设备暂时无法处理,比如硬件忙,则返回1。这时如果dev->tbusy置为非0,则系统认为硬件忙,要等到dev->tbusy置0以后才会再次发送。tbusy的置0任务一般由中断完成。硬件在发送结束后产生中断,这时可以把tbusy置0,然后用mark_bh()调用通知系统可以再次发送。在发送不成功的情况下,也可以不置dev->tbusy为非0,这样系统会不断尝试重发。如果hard_start_xmit发送不成功,则不要释放sk_buff。
  传送下来的sk_buff中的数据已经包含硬件需要的帧头。所以在发送方法里不需要再填充硬件帧头,数据可以直接提交给硬件发送。sk_buff是被锁住的(locked),确保其他程序不会存取它。
  
  2.2.5 接收(reception)
  驱动程序并不存在一个接收方法。有数据收到应该是驱动程序来通知系统的。一般设备收到数据后都会产生一个中断,在中断处理程序中驱动程序申请一块sk_buff(skb),从硬件读出数据放置到申请好的缓冲区里。接下来填充sk_buff中的一些信息。skb->dev = dev,判断收到帧的协议类型,填入skb->protocol(多协议的支持)。把指针skb->mac.raw指向硬件数据然后丢弃硬件帧头(skb_pull)。还要设置skb->pkt_type,标明第二层(链路层)数据类型。可以是以下类型:
  PACKET_BROADCAST : 链路层广播
  PACKET_MULTICAST : 链路层组播
  PACKET_SELF : 发给自己的帧
  PACKET_OTHERHOST : 发给别人的帧(监听模式时会有这种帧)
  
  最后调用netif_rx()把数据传送给协议层。netif_rx()里数据放入处理队列然后返回,真正的处理是在中断返回以后,这样可以减少中断时间。调用netif_rx()以后,驱动程序就不能再存取数据缓冲区skb。
  
  2.2.6 硬件帧头(hard_header)
  硬件一般都会在上层数据发送之前加上自己的硬件帧头,比如以太网(Ethernet)就有14字节的帧头。这个帧头是加在上层ip、ipx等数据包的前面的。驱动程序提供一个hard_header方法,协议层(ip、ipx、arp等)在发送数据之前会调用这段程序。
  硬件帧头的长度必须填在dev->hard_header_len,这样协议层回在数据之前保留好硬件帧头的空间。这样hard_header程序只要调用skb_push然后正确填入硬件帧头就可以了。
  在协议层调用hard_header时,传送的参数包括(2.0.xx):数据的sk_buff,device指针,protocol,目的地址(daddr),源地址(saddr),数据长度(len)。数据长度不要使用sk_buff中的参数,因为调用hard_header时数据可能还没完全组织好。saddr是NULL的话是使用缺省地址(default)。daddr是NULL表明协议层不知道硬件目的地址。如果hard_header完全填好了硬件帧头,则返回添加的字节数。如果硬件帧头中的信息还不完全(比如daddr为NULL,但是帧头中需要目的硬件地址。典型的情况是以太网需要地址解析(arp)),则返回负字节数。hard_he
推荐阅读
  • 本文介绍了一种解决方案,当笔记本电脑不具备作为无线接入点的能力时,如何通过开启Android手机的便携WLAN热点功能,使笔记本能够连接到手机并共享其网络资源,从而实现上网。文中详细描述了在Linux系统下配置的具体步骤。 ... [详细]
  • Linux 文件系统结构详解
    本文详细介绍了Linux操作系统的文件系统结构,包括其独特的树状目录体系、根目录的作用、目录与磁盘分区的关系等,并对各主要目录的功能进行了深入解析。 ... [详细]
  • 本文介绍了如何在 Linux 系统上构建网络路由器,特别关注于使用 Zebra 软件实现动态路由功能。通过具体的案例,展示了如何配置 RIP 和 OSPF 协议,以及如何利用多路由器查看工具(MRLG)监控网络状态。 ... [详细]
  • 本文探讨了在Java应用中实现线程池优雅关闭的两种方法,包括使用ShutdownHook注册钩子函数以及通过SignalHandler处理信号量。每种方法都提供了具体的代码示例,并讨论了可能遇到的问题及解决方案。 ... [详细]
  • 本文详细介绍了如何在VMware环境下安装CentOS 7 Minimal,并成功配置GNOME桌面环境的过程。包括解决网络连接问题和设置默认图形界面等关键步骤。 ... [详细]
  • grep、sed、awk一、grep的用法1、grep简介grep是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。grep包 ... [详细]
  • OpenWrt 是一款高度可定制的嵌入式 Linux 发行版,广泛应用于无线路由器等领域,拥有超过百个预装软件包。本文详细探讨如何在 OpenWrt 上通过 Luci 构建自定义模块,以扩展其功能。 ... [详细]
  • Python作为一种广泛使用的高级编程语言,以其简洁的语法、强大的功能和丰富的库支持著称。本文将详细介绍Python的主要特点及其在现代软件开发中的应用。 ... [详细]
  • ipvsadm命令简介:ipvsadm是LVS在应用层的管理命令,我们可以通过这个命令去管理LVS的配置。在fedora14、Linux6.0之后系统中 ... [详细]
  • 本文详细探讨了当前主流的两种系统架构——C/S(客户端/服务器)与B/S(浏览器/服务器)架构的特点、优缺点及未来的发展趋势。 ... [详细]
  • Kodi(原名XBMC)是一款由XBMC基金会开发的免费开源媒体播放器应用,支持多种操作系统和硬件平台。该软件以其强大的多媒体处理能力和用户友好的界面受到广泛欢迎。 ... [详细]
  • 导读上一篇讲了zsh的常用字符串操作,这篇开始讲更为琐碎的转义字符和格式化输出相关内容。包括转义字符、引号、print、printf的使用等等。其中很多内容没有必要记忆,作为手册参 ... [详细]
  • 探索PWA H5 Web App优化之路(Service Worker与Lighthouse的应用)
    本文探讨了如何通过Service Worker和Lighthouse工具来优化PWA H5 Web App,旨在提升用户体验,包括提高加载速度、增强离线访问能力等方面。 ... [详细]
  • 本文详细介绍了MySQL在Linux环境下的主从复制技术,包括单向复制、双向复制、级联复制及异步复制等多种模式。主从复制架构中,一个主服务器(Master)可与一个或多个从服务器(Slave)建立连接,实现数据的实时同步。 ... [详细]
  • Redis 教程01 —— 如何安装 Redis
    本文介绍了 Redis,这是一个由 Salvatore Sanfilippo 开发的键值存储系统。Redis 是一款开源且高性能的数据库,支持多种数据结构存储,并提供了丰富的功能和特性。 ... [详细]
author-avatar
baby小明君
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有