网络设备数据结构--device,它是网络驱动程序的最重要的部分,也是理解Linux网络接口的关键,
它的源代码 保存在 include /
linux / netdevice.h中,这个结构比较庞大,在此不予列出,仅仅对主要的域给予解释。
所有的网络设备的信息和操作都保存在设备数据结构中。每注册一个网络设备,
都需要提供数据结构中各个域的数据,这些域的含义下面将具体解释,其中,也包括对网络设备的设置。
1.名称
name 域指网络设备的名称,我们应该按上面讨论的命名方式为设备起名。该域也可以为空,这种情况下系统自动地分配一个ethn名字。 在 Linux 2.0版本以后, 我们可以用 dev_make_name("eth")
函数来为设备命名。
2.总线接口参数
总线接口参数用来设置设备在设备地址空间的位置。
irq :指设备使用的中断请求号(IRQ),它通常在启动时或被初始化函数设置。如果设备没有分配中断请求号,该域可以置0。中断请求号也可以设置为变量,由系统自动搜索一个空闲的中断请求号分配给该设备。 网络设备驱动程序通常使用一个全局整型变量 irq
表示中断号,因此用户可以使用“ insmod
mydevice irq=
base_addr(基地址):指设备占用的基本输入输出(I/O)地址空间。如果设备没有被分配 I/O地址或该设备运在一个没有I/O空间概念的系统上,该域就置0。当该地址由用户设置时,它通常用一个全局变量 io 来表示 。I/O接口地址也可以由 ifconfig 设置。
网络设备存在着两个硬件共享内存空间的情况,例如 ISA 总线和以太网卡共享内存空间。在网络设备的 device 数据结构中有四个相关的域。在共享内存时, rmem_start 和 rmem_end
域就被舍弃,并且置0; mem_start 和 mem_end 两个域标识设备共享内存块的起始地址和结束地址。
如果没有共享内存的情况,上面两个域就置0。有一些设备允许用户设置内存地址,我们通常用一个全局变量 mem 表示。
dma :标志设备正在使用的DMA通道。Linux
允许DMA(象中断一样)被系统自动探测。如果没有使用DMA通道或DMA通道没有设置,该域就置0。(最新的PC主版上, ISA 总线 DMA 通道0 被硬件占用,它没有和内存的刷新联系起来。) 如果由用户设置DMA通道,通常使用一个全局变量 dma 来表示。
我们应该认识到,上面提到的这些设备硬件信息都是从用户角度来对网络设备进行控制,它们和设备的内部函数功能是一样的。如果不注册它们,它们就有可能被重用,因此设备驱动程序必须分配并注册I/O,DMA 和中断向量这些参数。这些操作和其他设备驱动程序都用到相同的内核函数,关于具体的操作过程请参阅设备驱动程序一章相关内容。
if_port : 标识一些多功能网络设备的类型,例如 combo Ethernet boards 。
3.协议层参数
为了使网络协议层能智能化地执行任务,网络设备驱动程序也需要协议层提供一些性能标志和变量,这些参数都保存在设备数据结构中。
mtu :指网络接口的最大负荷,也就是网络可以传输的最大的数据包尺寸,它不包括设备自身提供的低层数据头的大小,该值常被协议层(如IP协议)使用,用来选择大小合适数据包进行发送。
family: 指该设备支持的地址族。常用的地址族是 AF_INET ,关于地址族的概念和具体解释,请参阅本章第三节套接字。 Linux 允许一个设备同时使用多个地址族,具体情况可以参考关于BSD网络API 方面的书籍。
interface hardware type :指设备所连接的物理介质的硬件接口类型,它的值来自物理介质类型表。支持ARP协议的物理介质,它们的接口类型被ARP协议使用(参看RCF1700);其他的接口类型是为其他物理层定义的。新的接口类型,只有当它对内 核和net-tools(注:net-tools也是一段源代码,它随内核一起发布,用来对Linux 网络进行调试) 都是必需时才会添加。包含象
ifconfig 这样的工具包可以对该域进行解码。该域的定义形式为:
该定义来自RFC1700(RFC即 Request For Comments 用户数据报协议)
ARPHRD_NETROMARPHRD_ETHER
10 和
ARPHRD_EETHER 实验用网卡 (没有使用)
ARPHRD_AX25
AX.25 2级 接口
ARPHRD_PRONET
PROnet token ring (没有使用)
ARPHRD_CHAOS ChaosNET (没有使用)
ARPHRD_IEE802
802.2 networks notably token ring
ARPHRD_ARCNET
ARCnet 接口
ARPHRD_DLCI
Frame Relay DLCI
由 Linux定义:
ARPHRD_SLIP
Serial Line IP protocol
ARPHRD_CSLIP
SLIP with VJ header compression
ARPHRD_SLIP6
6bit encoded SLIP
ARPHRD_CSLIP6 6bit
encoded header compressed SLIP
ARPHRD_ADAPT
SLIP interface in adaptive mode
ARPHRD_PPP
PPP interfaces (async and sync)
ARPHRD_TUNNEL IPIP
tunnels
ARPHRD_TUNNEL6 IPv6 over
IP tunnels
ARPHRD_FRAD
Frame Relay Access Device
ARPHRD_SKIP
SKIP encryption tunnel
ARPHRD_LOOPBACK Loopback device
ARPHRD_LOCALTLK Localtalk apple
networking device
ARPHRD_METRICOM Metricom Radio
Network
上面标注“没有使用”的接口,是因为它们虽然被定义了类型,但是目前还没有支持它们的
net-tools。Linux 内核为以太网和令环网提供了额外的支持例程。
pa_addr: 用来保持IP 地址
pa_brdaddr : 网络广播地址
pa_dstaddr : 点对点连接中的目标地址
pa_mask :
网络掩码
上面所有域都被初始化为 0。
pa_alen: 保存一个地址的长度,就 IP 地址而言,应该初始化为4。
4.链接层变量
hard_header_len :标识在网络缓冲区的头部,为硬件帧头准备的空间大小。这个值和将来添加的硬件帧头的字节数不一定相等。这样当sk_buff到达设备之前,就事先为硬件帧头准备了一块空间(scratch pad) 。
在1.2.x系列的内核版本中,skb->data 指针指向整个缓冲区的开始,没有真正指向数据区,因此必须小心不能将“ scratch pad ”也发送出去。 这也暗示着hard_header_len的长度必须大于硬件帧头的长度(硬件帧头可以和数据相临)。在1.3.x以后的版本里,问题变的非常容易,因为sk_buff 可以设置得足够大,不会出现空间不够的情况。至于这块空间
(scratch pad)的建立,要用到本章第四节中的
skb_push( ) 函数。
物理介质的地址由分别保存在 dev_addr和 broadcast 两个域中,我们用字符数组来保存物理地址。如果物理地址的长度比数组的长度小 ,那么物理地址在数组中就从左边开始保存,右边可以空余。 addr_len 域用来存储物理地址的长度。因为许多介质没有物理地址,该域就置0。还有一些其他类型的接口,物理地址必须由用户程序设置,对接口物理地址的设置可以用 ifconfig 工具。这种情况下,物理地址就不必进行初始化设置,但是我们从源代码可以看出,如果在一个设备物理地址没有被设置,就不允许它进行传输数据。
5.接口标志
接口标志包含一些接口属性,其中一些是为了提高网络接口的兼容性而设的,因为这些标志并没有直接的用途。内核中用到的接口标志有:
IFF_UP:
接口已经激活。
在Linux中, IFF_RUNNIN 和 IFF_UP 标志基本上是成对出现,因为两者是相辅相成的。如果一个接口没有被标识
IFF_UP,它就不能够被删除。这和BSD不同,在BSD中,一个接口如果没有收到数据,就不会标识 IFF_UP 。
IFF_BROADCAST: 设置设备广播地址有效
。
IFF_DEBUG:
标识设备调试能力打开。目前并不使用。
IFF_LOOPBACK: 只有回环设备(lo)才使用该标志。
IFF_POINTOPOINT: 该设备是点对点链路设备(如 SLIP 或 PPP)。 通常点对点的连接没有子网掩码和广播地址,但是如果需要可以激活。
IFF_RUNNING: 见 IFF_UP
IFF_NOARP:
接口不支持 ARP 协议。这样的接口必须有一个静态的地址转换表,或者它不需要执行地址映射。 NetROM 接口就是一个很好的例子。
5.数据包队列
该队列包含了等待由该网络设备发送的
sk_buff 数据包。发送到网络设备接口的数据包都由内核中协议层的代码排成队列。
在每一个设备中, 数据包 按优先级顺序存放在 buffs [ ] 数组里。它们完全有内核代码控制,但是在启动时由设备自身进行初始化,初始化代码为:
int ct=0;
while(ct < DEV_NUMBUFFS)
{
skb_queue_head_init(&dev->buffs[ct]);
ct++;
}
其它域被初始化为0。
网络设备通过设置
dev->tx_queue_len 来决定传输队列的长度。通常以太网的队列长度为100,serial lines 为10 。