《Linux Device Drivers》 第十七章 网络驱动程序——note
- 基本介绍
- 第三类是标准的网络接口Linux设备,本章介绍的内核,其余的交互网络接口描述
- 网络接口,必须使用特定的内核数据结构本身注册,与外部分组交换数据线打电话时准备
- 经常使用的文件上的网络接口操作是没有意义的,因此在它们身上无法体现Unix的“一切都是文件”的思想
- 网络驱动程序异步自外部世界的数据包
- 网络设备向内核请求把外部获得的数据包发送给内核
- Linux内核中的网络子系统被设计成全然与协议无关
- 在网络世界中使用术语“octet”指一组8个的数据位。它是能为网络设备和协议所能理解的最小单位
- 协议头(header)是在数据包中的一系列字节,它将通过网络子系统的不同层
- 连接到内核
- loopback.c、plip.c和e100.c
- 设备注冊
- 驱动程序对每一个新检測到的接口,向全局的网络设备链表中插入一个数据结构
- <linux/netdevice.h>
- struct net_device
- struct net_device *alloc_netdev(int sizeof_priv, const char *name, void (*setup) (struct net_device *));
- name是接口的名字,这个名字能够使用类似printf中%d的格式,内核将用下一个可用的接口号替代%d
- <linux/etherdevie.h>
- struct net_device *alloc_etherdev(int sizeof_priv);
- 光纤通道设备使用alloc_fcdev(<linux/fcdevice.h>)
- FDDI设备使用alloc_fddidev(<linux/fddidevice.h>)
- 令牌环设备使用alloc_trdev(<linux/trdevice.h>)
- register_netdev函数
- 初始化每一个设备
- example
- ether_setup(dev);
- dev->open = open_function;
- dev->stop = release_function;
- dev->set_config = config_function;
- dev->hard_start_xmid = tx_function;
- dev->do_ioctl = ioctl_function;
- dev->get_stats = stats_function;
- dev->rebuild_header = rebuild_header_function;
- dev->hard_header = header_function;
- dev->tx_timeout = tx_timeout_function;
- dev->watchdog_timo = timeout;
- dev->flags |= IFF_NOARP;
- dev->features |= NETIF_F_NO_CSUM;
- dev->hard_header_cache = NULL;
- priv = netdev_priv(dev);
- example
- 模块的卸载
- unregister_netdev函数从系统中删除接口
- free_netdev函数将net_device结构返回给系统
- net_device结构细节
- 全局信息
- char name[IFNAMSIZ];
- unsigned long state;
- struct net_device *next;
- int (*init) (struct net_device *dev);
- 硬件信息
- unsigned long rmem_end;
- unsigned long rmem_start;
- unsigned long mem_end;
- unsigned long mem_start;
- unsigned long base_addr;
- unsigned char irq;
- unsigned char if_port;
- unsigned char dma;
- 接口信息
- drivers/net/net_init.c
- void ltalk_setup(struct net_device *dev);
- void fs_setup(struct net_device *dev);
- void fddi_setup(struct net_device *dev);
- void hippi_setup(struct net_device *dev);
- void tr_setup(struct net_device *dev);
- unsigned short hard_header_len;
- 对以太网接口,该值是14
- unsigned mtu;
- 最大传输单元,以太网的MTU是1500个octet
- unsigned long tx_queue_len;
- unsigned short type;
- ARP使用type成员推断接口所支持的硬件地址类型
- <linux/if_arp.h>
- unsigned char addr_len;
- unsigned char broadcast[MAX_ADDR_LEN];
- unsigned char dev_addr[MAX_ADDR_LEN];
- unsigned short flags;
- int features;
- 该标志成员是一个位掩码
- IFF_前缀表示“接口标志”,有效的标志定义在<linux/if.h>
- 设备方法
- 网络接口的设备方法可划分为两个类型:主要的和可选的
- 基本方法
- int (*open) (struct net_device *dev);
- int (*stop) (struct net_device *dev);
- int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev);
- int (*hard_header) (struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);
- int (*rebuild_header) (struct sk_buff *skb);
- void (*tx_timeout) (struct net_device *dev);
- struct net_device_stats *(*get_stats) (struct net_device *dev);
- int (*set_config) (struct net_device *dev, struct ifmap *map);
- 可选方法
- int (*poll) (struct net_device *dev, int *quota);
- void (*poll_controller) (struct net_device *dev);
- int (*do_ioctl) (struct net_device *dev, struct ifreq *ifr, int cmd);
- void (*set_multicast_list) (struct net_device *dev);
- int (*set_mac_address) (struct net_device *dev, void *addr);
- int (*change_mtu) (struct net_device *dev, int net_mtu);
- int (*header_cache) (struct neighbour *neigh, struct hh_cache *hh);
- int (*header_cache_update) (struct hh_cache *hh, struct net_device *dev, unsigned char *haddr);
- int (*hard_header_parse) (struct sk_buff *skb, unsigned char *haddr);
- 工具成员
- unsigned long trans_start;
- unsigned long last_rx;
- int watchdog_timeo;
- void *priv;
- struct dev_mc_list *mc_list;
- int mc_count;
- spinlock_t xmit_lock;
- int xmit_lock_owner;
- 全局信息
- 打开和关闭
- 在使用ifconfig向接口赋予地址时,要运行两个任务
- 首先,通过ioctl(SIOCSIFADDR)赋予地址
- 然后,通过ioctl(SIOCSIFFLAGS)设置dev->flag中的IFF_UP标志以打开接口
- 对设备而言,无需对ioctl(SIOCSIFADDR)做不论什么工作。后一个命令会调用设备的open方法
- 在接口被关闭时,ifconfig使用ioctl(SIOSIFFLAGS)来清除IFF_UP标志,然后调用stop函数
- 此外。还要运行其它一些步骤
- 首先,在接口有够和外界通讯之前,要将硬件地址(MAC)从硬件设备拷贝到dev->dev_addr
- 应该启动接口的传输队列
- void netif_start_queue(struct net_device *dev);
- 在使用ifconfig向接口赋予地址时,要运行两个任务
- 数据包传输
- 不管何时内核要传输一个数据包,它都会调用驱动程序的hard_start_transmit函数将数据放入外发队列
- 内核处理的每一个数据包位于一个套接字缓冲区结构(sk_buff)中。该结构定义在<linux/skbuff.h>中
- 传递经全hard_start_xmit的套接字缓冲区包括了物理数据包,并拥有完整的传输层数据包头
- 该传输函数仅仅运行了对数据包的一致性检查。然后通过硬件相关的函数数据传输
- 假设运行成功,则hard_start_xmit返回0
- 控制并发传输
- 通过net_device结构中的一个自旋锁获得并发调用时的保护
- 实际的硬件接口是异步数据传输包的,并且可用来保存外发数据包的存储空间很有限
- void netif_wake_queu(struct net_device *dev);
- 通知网络系统可再次開始数据传输包
- void netif_tx_disable(struct net_device *dev);
- 禁止数据包的传送
- 传输超时
- 假设当前的系统时间超过设备的trans_start时间至少一个超时周期,网络层将终于调用驱动程序的tx_timeout函数
- Scatter/Gather I/O
- 在网络上为传输工作创建数据包的过程,包含了组装多个数据片段的过程
- 假设负责发送数据包的网络接口实现了分散/聚焦I/O,则数据包就不用组装成一个大的数据包
- 分散/聚焦I/O还能用“零拷贝”的方法。把网络数据直接从用户缓冲区内传输出来
- 假设在device结构中的feature成员内设置了NETIF_F_SG标志位。内核才将分散的数据包传递给hard_start_xmit函数
- struct skb_frag_struct
- struct page *page;
- __u16 page_offset;
- __u16 size;
- 数据包的接收
- 从网络上接收数据要比数据传输复杂一点。由于必须在原子上下文中分配一个sk_buff并传递给上层处理
- 网络驱动程序实现了两种模式接收数据包:中断驱动方式和轮询方式
- 过程
- 第一步是分配一个保存数据包的缓冲区
- dev_alloc_skb
- 检查dev_alloc_skb函数的返回值
- 一旦拥有一个合法的skb指针,则调用memcpy将数据包数据复制到缓冲区内
- 最后。驱动程序更新其统计计数器
- 第一步是分配一个保存数据包的缓冲区
- 接收数据包过程中的最后一个步骤由netif_rx运行
- 中断处理例程
- 接口在两种可能的事件下中断处理器
- 新数据包到达
- 外发数据包的传输已经完毕
- 通常中断例程通过检查物理设备中的状态寄存器,以区分新数据包到达中断和传输数据完成中断
- 传输结束时。统计信息要被更新,并且要将套接字缓冲区返回全系统
- dev_kfree_skb(struct sk_buff *skb);
- dev_kfree_skb_irq(struct sk_buff *skb);
- dev_kfree_skb_any(struct sk_buff *skb);
- 接口在两种可能的事件下中断处理器
- 不使用接收中断
- 为了能提高Linux在宽带系统上的性能。网络子系统开发人员创建了第二种基于轮询方法的接口(称之为NAPI)
- 停止使用中断会减轻处理器的负荷
- struct net_device的poll成员必须设置为驱动程序的轮询函数
- 当接口通知数据到达的时候,中断程序不能处理该数据包,相反它还要禁止接收中断,而且告诉内核。从如今開始启动轮询接口
- 用netif_receive_skb函数将数据包传递给内核,而不是使用netif_rx
- 调用netif_rx_complete关闭轮询函数
- 链路状态的改变
- 大多数涉及实际的物理连接的网络技术提供载波状态信息,载波的存在意味着硬件功能是正常的
- void netif_carrier_off(struct net_device *dev);
- void netif_carrier_on(struct net_device *dev);
- int netif_carrier_ok(struct net_device *dev);
- 用来检測当前的载波状态
- 套接字缓冲区
- <linux/skbuff.h>
- 重要的成员
- struct net_device *dev
- union { /* … */ } h;
- union { /* … */ } nh;
- union { /* … */ } mac;
- unsigned char *head;
- unsigned char *data;
- unsigned char *tail;
- unsigned char *end;
- unsigned int len;
- unsigned int data_len;
- unsigned char ip_summed;
- unsigned char pkt_type;
- shinfo (struct sk_buff *skb);
- unsigned int shinfo(skb)->nr_frags;
- skb_frag_t shinfo(skb)->frags;
- 操作套接字缓冲区的函数
- struct sk_buff *alloc_skb(unsigned int len, int priority);
- struct sk_buff *dev_alloc_skb(unsigned int len);
- void kfree_skb(struct sk_buff *skb);
- void dev_kfree_skb(struct sk_buff *skb);
- void dev_kfree_skb_irq(struct sk_buff *skb);
- void dev_kfree_skb_any(struct sk_buff *skb);
- unsigned char *skb_put(struct sk_buff *skb, int len);
- unsigned char *__skb_put(struct sk_buff *skb, int len);
- unsigned char *skb_push(struct sk_buff *skb, int len);
- unsigned char *__skb_push(struct sk_buff *skb, int len);
- int skb_tailroom(struct sk_buff *skb);
- int skb_headroom(struct sk_buff *skb);
- void skb_reserve(struct sk_buff *skb, int len);
- unsigned char *skb_pull(struct sk_buff *skb, int len);
- int skb_is_nonlinear(struct sk_buff *skb);
- int skb_headlen(struct sk_buff *skb);
- void *kmap_skb_frag(skb_frag_t *frag);
- void kunmap_skb_frag(void *vaddr);
- MAC地址解析
- 在以太网中使用ARP
- ARP由内核维护,而以太网接口不须要做不论什么特殊工作就能支持ARP
- 重载ARP
- 假设设备希望使用经常使用的硬件头,而不执行ARP,则须要重载默认的dev->hard_header函数
- 非以太网头
- 硬件头中除目标地址之外,还包括其它一些信息。当中最重要的是通信协议
- drivers/net/appletalk/cops.c
- drivers/net/irda/smc_ircc.c
- drivers/net/pp_generic.c
- 在以太网中使用ARP
- 定制ioctl命令
- 当为某个套接字使用ioctl系统调用时。命令号是定义在<linux/sockios.h>中的某个符号
- 函数sock_ioctl直接调用一个协议相关的函数
- 不论什么协议层不能识别的ioctl命令都会传递到设备层
- 这些设备相关的ioctl命令从用户空间接受第三个參数。即一个struct ifreq *指针
- <linux/if.h>
- 统计信息
- 驱动程序须要的最后一个函数是get_stats,这个函数返回设备统计结构的指针
- struct net_device_stats
- unsigned long rx_packets;
- unsigned long tx_packets;
- unsigned long rx_bytes;
- unsigned long tx_bytes;
- unsigned long rx_errors;
- unsigned long tx_errors;
- unsigned long rx_dropped;
- unsigned long tx_dropped;
- unsigned long collisions;
- unsigned long multicast;
- 组播
- 对以太网而言,组播地址在目标地址的第一个octet的最低位设置为1,而全部设备板卡将自己的硬件地址的对应位清零
- 内核在随意给定时刻均要跟踪组播地址
- 驱动程序实现组播清单的方法。在某种程序上依赖于底层硬件的工作方式
- 通常来说,考虑组播时。硬件可划分为三类
- 不有处理组播的接口
- 可以区分组播数据包和其它数据包的接口
- 可以为组播地址进行硬件检測的接口
- 对组播的内核支持
- 对组播数据包的支持由例如以下几项组成:一个设备函数、一个数据结构以及若干设备标志
- void (*dev_set_multicast_list) (struct net_device *dev);
- struct dev_mc_list *dev->mc_list;
- int dev->mc_count;
- <linux/netdevice.h>
- struct dev_mc_list
- struct dev_mc_list *next
- __u8 dmi_addr[MAX_ADDR_LEN];
- unsigned char dmi_addrlen;
- int dmi_users;
- int dmi_gusers;
- 其它知识点具体解释
- 对介质无关接口的支持
- 介质无关接口(Media Independent Interface, MII)是一个IEEE802.3标准,它描写叙述了以太网收发器是怎样与网络控制器连接的
- <linux/mii.h>
- int (*mdio_read) (struct net_device *dev, int phy_id, int location);
- void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
- drivers/net/mii.c
- ethtool支持
- ethtool是为系统管理员提供的用于控制网络接口的工具
- 仅仅有当驱动程序支持ethtool时。使用ethtool才干控制包含速度、介质类型、双工操作、DMA设置、硬件检验、LAN唤醒操作在内的很多接口參数
- http://sf.net/projects/gkernel/
- <linux/ethtool.h>
- struct ethtool_ops
- Netpoll
- 它出现的目的是让内核在网络和I/O子系统尚不能完整可用时,依旧能发送和接收数据包
- 用于网络控制台和远程内核调试
- 实现netpoll的驱动程序须要实现poll_controller函数,作用是在缺少设备中断时。还能对控制器响应
- 对介质无关接口的支持
版权声明:本文博客原创文章,博客,未经同意,不得转载。
《Linux Device Drivers》 第十七章 网络驱动程序——note的更多相关文章
- 《Linux Device Drivers》第八章 分配内存——note
本章主要介绍Linux内核的内存管理. kmalloc函数的内幕 不正确所获取的内存空间清零 分配的区域在物理内存中也是连续的 flags參数 <linux/slab.h> <lin ...
- 《Linux Device Drivers》第十四章 Linux 设备型号
基本介绍 2.6内核设备模型来提供的抽象叙述性描述的一般系统的结构,为了支持各种不同的任务 电源管理和系统关机 用户空间与通信 热插拔设备 设备类型 kobject.kset和子系统 kobject是 ...
- Linux内核设计第十七章笔记
第十七章 设备与模块 关于设备驱动和设备管理,四种内核成分 设备类型:在所有unix系统中为了统一普通设备的操作所采用的分类 模块:Linux内核中用于按需加载和卸载目标代码的机制 内核对象:内核数据 ...
- 《Linux Device Drivers》第十六章 块设备驱动程序——note
基本介绍 块设备驱动程序通过主传动固定大小数据的随机访问设备 Linux核心Visual块设备作为基本设备和不同的字符设备类型 Linux块设备驱动程序接口,使块设备最大限度地发挥其效用.一个问题 一 ...
- 《Linux Device Drivers》第十二章 PCI司机——note
一个简短的引论 它给这一章总线架构的高级概述 集中访问讨论Peripheral Component Interconnect(PCI,外围组件互连)外设内核函数 PCI公交车是最好的支持的内核总线 本 ...
- 《Linux Device Drivers》第十五章 内存映射和DMA——note
简单介绍 很多类型的驱动程序编程都须要了解一些虚拟内存子系统怎样工作的知识 当遇到更为复杂.性能要求更为苛刻的子系统时,本章所讨论的内容迟早都要用到 本章的内容分成三个部分 讲述mmap系统调用的实现 ...
- 《Linux Device Drivers》第十八章 TTY驱动程序——note
简单介绍 tty设备的名称是从过去的电传打字机缩写而来,最初是指连接到Unix系统上的物理或虚拟终端 Linux tty驱动程序的核心紧挨在标准字符设备驱动层之下,并提供了一系列的功能,作为接口被终端 ...
- 《Linux Device Drivers》第十一章 核心数据类型——note
基本介绍 因为Linux多平台特性,不管是哪一个重要驱动力应该是便携 与内核代码相关的核心问题应该是访问的同时是数据项的已知长度.能力和利用不同的处理器 内核使用的数据类型主要分为三类 类似int这种 ...
- linux device drivers ch03
ch03.字符设备驱动程序 编写驱动程序的第一步就是定义驱动程序为用户程序提供的能力(机制).接下来以scull(“Simple Character Utility for Loading Local ...
随机推荐
- 解决xShell4某些情况下按删除键会输出^H的问题
当我们用Xshell登录进入linux后,在普通模式下,对输入进行删除等操作没有问题. 而在执行中,按delete,backspace键时会产生^H等乱码问题. 这是由于编码不匹配的问题. 解决方法: ...
- Types of Windows
The Window's Real Estate Application's Instance A window is referred to as parent when it can be ...
- 使用VS插件在VS2012/2013上编辑和调试Quick-Cocos2d-x的Lua代码
vs 也能够做lua 开发,并进行代码调试 依照以下文档,调试没问题. 參考文档: 点击打开链接
- HelloGithub
<HelloGithub月刊>第一期 <HelloGithub月刊> 因为现在这个项目只有我自己做,只敢叫“月刊”,希望有志同道合者,快点加入到这个项目中来!同时,如果您有 ...
- 无状态TCP的ip_conntrack
Linux的ip_conntrack实现得过于沉重和精细.而实际上有时候,根本不需要在conntrack中对TCP的状态进行跟踪,只把它当UDP好了,我们的需求就是让系统可以将一个数据包和一个五元组标 ...
- HTML5线性图表 图表数据区域可着色
这是一款基于Canvas的HTML5图表应用,在图表数据初始化的时候伴随动画效果. 在线演示: 点击演示 源代码下载: 点击下载 核心jQuery代码: var myData = { labels ...
- Apache配置虚拟文件夹
作为一个Android开发人员,一直以为,至少应该有一个server语言,最近慢慢学习php,当然学习Apache使用.本文介绍Win7环境下,怎样配置Apache的虚拟文件夹. 首先,找到我们Apa ...
- Hdu 4738【求无向图的桥】.cpp
题目: 曹操在长江上建立了一些点,点之间有一些边连着.如果这些点构成的无向图变成了连通图,那么曹操就无敌了.刘备为了防止曹操变得无敌,就打算去摧毁连接曹操的点的桥.但是诸葛亮把所有炸弹都带走了,只留下 ...
- Ubuntu12.04下使用virtualbox4.3.12 amd64安装XP系统教程
首先第一步打开已安装好的Virtualbox4.3.12,效果图例如以下: 第二步:点击新建进入新建虚拟电脑界面,填写名称,选择类型和版本号(我这里使用的三XP 64bit): 第三步:选择内存大小, ...
- 服务器编程入门(2)IP协议详解
问题聚焦: IP协议是TCP/IP协议族的核心协议,也是socket网络编程的基础之一.这里从两个方面较为深入地探讨IP协议: 1,IP头部信息(指定IP通信的源端IP地址,目的端IP ...