以服务于中国广大创业者为己任,立志于做最好的创业网站。

标签云创业博客联系我们

导航菜单

互联网的基本认识,互联网+的含义是什么

  

  #网络层次结构   

  

  Linux网络设备驱动程序与字符设备和块设备非常不同。   

  

  1.字符设备和块设备对应于/dev下的设备文件。网络设备中没有这样的设备文件。通过套接字访问网络。虽然也使用读、读、写系统调用,但这些调用只作用于软件对象。   

  

  2.Block设备只响应内核的请求,而网络驱动程序异步接收外界的数据包,向内核发送请求给内核。   

  

  linux内核中网络子系统的设计基于设备无关和协议无关的思想。也就是不管什么网卡驱动或者网络协议,都对应一个统一的驱动。   

  

  Linux网络协议栈有四层:网络协议接口层、网络设备接口层、设备驱动功能层和网络设备媒体层。   

  

     

  

  以下只是对linux如何实现网络设备的设备无关性和协议无关性的分析。   

  

  网络协议接口层:   

  

  为上层协议提供透明的数据包发送和接收接口。协议无关:发送数据包时,ARP协议或IP协议会调用本层的dev_queue_xmit()函数发送数据包。上层通过netif_rx()接收数据包。具体的协议处理是在上级网络协议处理。这需要一个非常重要的结构。   

  

  sk_buff。   

  

  网络设备接口层:为千变万化的网络设备定义了统一抽象的数据结构net_device结构,在软件层面实现了各种硬件的统一。设备无关。   

  

  net_device结构是指内核中的一个网络设备,网络设备驱动程序只需要在net_device中填充特定成员,注册net_device,就可以将硬件操作功能与内核挂钩。使用注册、注销、初始化等一系列统一功能。   

  

  在设备驱动功能层:网络设备中填充成员。管理物理网络设备。   

  

  包括诸如设备打开、停止和传输的操作。因为网络数据包的接收可以通过中断产生,所以设备驱动功能层的另一个主题部分是中断处理功能,它负责读取硬件上接收到的数据包,并将其传输到上层协议。   

  

  网络设备与媒介层:对应于实际的物理器件,包括器件寄存器的描述、寄存器读写功能等。   

  

  #网络协议   

  

  这里,我们主要发送和接收数据包,并使用如下函数的原型:   

  

  dev _ queue _ xmit(struct sk _ buff * skb);int netif _ rx(struct sk _ buff * skb);   

  

  这里我们使用一个skb_buff结构,在include/linux/skbuff.h中定义,意思是“socket buffer”,用来在linux网络子系统的各层之间传输数据。   

  

  sk_buff中的重要数据成员   

  

  struct设备* dev正在处理包_ _ U32SAD的设备;R//IP元地址_ _ u32 daddr//IP目的地址_ _ u32 raddr//IP路由器地址无符号char * head//分配空间的开始为无符号char *数据;//有效数据的开始无符号字符*尾部;//有效数据结束无符号字符*结束;//分配空间结束无符号长len//有效数据的长度   

  

  Sk_buff操作   

  

  1.分配:为协议栈代码分配一个sk_buff结构。   

  

  struct sk_buff *alloc_skb(无符号int len,int priority);struct sk_buff *dev_alloc_skb(无符号int len);   

  

  分配一个缓冲区。alloc_skb函数分配一个缓冲区,并将skb-data和skb-tail初始化为skb-head。参数len是数据缓冲区的空间大小,通常与L1_CACHE_BYTES对齐(ARM为32),参数priority是内存分配的优先级。dev_alloc_skb()函数分配具有GFP_ATOMIC优先级的skb。   

  

  2.发布:   

  

  void kfree _ skb(struct sk _ buff * skb);void dev _ kfree _ skb(struct sk _ buff * skb);   

  

  kfree_skb()函数用于Linux内核,而dev_kfree_skb()最适合用于网络设备驱动程序。   

  

  sk_buff中更重要的成员是指向数据包中数据的指针,用于寻址数据包中的数据。head指向已分配空间的开头,data指向有效八位字节的开头,tail指向有效八位字节的结尾,end指向tail可以到达的最大地址。如果不这样做,应该分配一个固定大小的缓冲区。如果缓冲区不够,应该申请一个更大的缓冲区,复制进去再添加,这样会降低性能。   

  

  3.更改:   

  

unsigned char *skb_put(struct sk_buff *skb, int len);

  

将taill指针向后移动len长度,并返回tail移动之前的值。用于向skb有效数据区域末尾添加数据。

  

unsigned char *skb_push(struct sk_buff *skb, int len);

  

将data指针向前移动len长度。并返回移动之后的值。用于向skb有效数据区域前端添加数据(包头)。

  

unsigned char *skb_pull(struct sk_buff *skb, int len);void skb_reserve(struct sk_buff ×skb, int len);

  

# 网络设备

  

系统检测到了PCI设备,并启用它,但它只是一支硬件设备(网卡设备),而Linux的网络协议栈只认得[网络设备]。[网络设备]是一支逻辑设备,由结构net_device表征。也就是说,网络协议栈向[网络设备]发出命令,而[网络设备]的驱动将这些命令传递到PCI[网卡设备]。表3列出了结构net_device的一些重要数据域,

  

struct net_device { char *name; unsigned long base_addr; unsigned char addr_len; unsigned char dev_addr[MAX_ADDR_LEN]; unsigned char broadcast[MAX_ADDR_LEN]; unsigned short hard_header_len; unsigned char irq; int (*open) (struct net_device *dev); int (*stop) (struct net_device *dev); int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev); struct net_device_stats* (*get_stats)(struct net_device *dev); void *priv; };

  

以上是结构net_device部分重要成员,以下简介这些成员的用途:

  

* name – 设备的名称。如果名称的第一个字符是null,那么register_netdev分配给它取名为“ethN”,其中N是合适的数字。例如,如果您的系统已经有eth0和eth1,您的设备将被命名的eth2。

  

* base_addr – I/O基地址。

  

* addr_len – 硬件地址(MAC地址)的长度。以太网接口地址长度为6字节。

  

* dev_addr – 硬件地址(以太网地址或MAC地址)

  

* broadcast – 设备的广播地址。以太网接口的广播地址是FF:FF:FF:FF:FF:FF

  

* hard_header_len – “硬件头的长度”是数据包硬件头的八位位组(octets)的数量。 以太网接口的hard_header_len的值是14

  

* IRQ – 分配的中断号

  

* open – 这是打开设备函数的指针。这个函数在用ifconfig命令激活设备时被调用,例如“ifconfig eth0 up”。 open函数负责向系统申请所需的系统资源需求(I/O端口,IRQ,DMA等),启用硬件和递增模块的使用计数。

  

* stop – 这是停止设备函数的指针。这个函数在用ifconfig命令停用设备时被调用,例如“ifconfig eth0 down”。 stop函数释放所有open函数获得的资源。

  

* hard_start_xmit – 此函数在传输线路上发送一个给定的数据包。该函数的第一个参数是指向结构sk_buff指针。结构sk_buff的是通过Linux网络协议栈的数据包。本文并不需要详细了解有关的sk_buff的结构的细节,你可以在下网址获得更多的结构sk_buff的信息:http://www.tldp.org/LDP/khg/HyperNews/get/net/net-intro.html。

  

* get_stats – 此函数提供了接口统计信息。命令“ifconfig eth0”的很多输出内容来自get_stats。

  

* priv – 驱动程序的私有数据域。驱动程序拥有这一数据域,并可以使用它。

  

特别注意,net_device没有接收数据包的成员函数,这是因为接收数据包是由设备的[中断处理程序]负责的

  

# 驱动的实现

  

1)初始化(init) 设备探测工作在init方法中进行,一般调用一个称之为probe方法的函数

  

初始化的主要工作时检测设备,配置和初始化硬件,最后向系统申请这些资源。此外填充该设备的dev结构,我们调用内核提供的ether_setup方法来设置一些以太网默认的设置。

  

2)打开(open)

  

open这个方法在网络设备驱动程序里是网络设备被激活时被调用(即设备状态由down变成up)实际上很多在初始化的工作可以放到这里来做。比如说资源的申请,硬件的激活。如果dev->open返回非0,则硬件状态还是down,注册中断、DMA等;设置寄存器,启动设备;启动发送队列一般注册中断都在init中做,但在网卡驱动程序中,注册中断大部分都是放在open中注册,因为要经常关闭和重启网卡

  

3)关闭(stop) stop方法做和open相反的工作 可以释放某些资源以减少系统负担 stop是在设备状态由up转为down时被调用

  

4)发送(hard_start_xmit)

  

在系统调用的驱动程序的hard_start_xmit时,发送的数据放在一个sk_buff结构中。一般的驱动程序传给硬件发出去。也有一些特殊的设备比如说loopback把数据组成一个接收数据在传送给系统或者dummy设备直接丢弃数据。如果发送成功,hard_start_xmit方法释放sk_buff。如果设备暂时无法处理,比如硬件忙,则返回1。

  

5)接收 驱动程序并存在一个接受方法。当有数据收到时驱动程序调用netif_rx函数将skb交给设备无关层。

  

一般设备收到数据后都会产生一个中断,在中断处理程序中驱动程序申请一块sk_buff(skb)从硬件中读取数据位置到申请号的缓冲区里。

  

接下来填充sk_buff中的一些信息。

  

中断有可能是收到数据产生也可能是发送完成产生,中断处理程序要对中断类型进行判断,如果是收到数据中断则开始接收数据,如果是发送完成中断,则处理发送完成后的一些操作,比如说重启发送队列。

  

接收流程: 1、分配skb=dev_alloc_skb(pkt->datalen+2) 2、从硬件中读取数据到skb

  

3、调用netif_rx将数据交给协议栈

  

> 原文链接:https://blog.csdn.net/viewsky11/article/details/53177592