1.Linux网络子体系
Linux网络子体系的顶部是体系调用接口层。它为用户空间供给的应用程序供给了一种拜访内核网络子体系的办法(socket)。坐落其下面是一个协议无关层,它供给一种通用的办法来运用传输层协议。然后是详细协议的完结,在Linux中包含内核的协议TCP,UDP,当然还有IP。然后是设备无关层,它供给了协议与设备驱动通讯的通用接口,最下面是设备的驱动程序。
设备无关接口将协议与各种网络驱动衔接在一起,这一层供给一组通用函数供底层网络设备驱动运用,让它们能够对高层协议栈进行操作。需求从协议层向设备发生数据,需求调用dev_queue_xmit函数,这个函数对数据进行列队,然后交由底层驱动程序的hard_start_xmit办法终究完结传输。接纳一般是运用netif_rx履行的。当底层设备程序接纳到一个报文(发生中止)时,就会调用neTIf_rx将数据上传至设备无关层。
下图为设备无关层到驱动层的体系结构
2.网络设备描绘(structnet_device)
每一个网络设备都由struct net_device来描绘,该结构可运用如下内核函数进行动态分配
struct net_device *alloc_net(intsizeof_priv, const char *mask, void(*setup)(struct net_deive *))
sizeof_priv是私有数据区巨细;mask是设备名,setup是初始化函数,在注册该设备时,该函数被调用。也便是net_deivce的init成员。
struct net_device *alloc_etherdev(intsizeof_priv)
这个函数和上面的函数不同之处在于内核知道会将该设备做一个以太网设备看待并做一些相关的初始化。
net_device结构可分为大局成员、硬件相关成员、接口相关成员、设备办法成员和共用成员等五个部分
首要大局成员
char name[INFAMSIZ]
设备名,如:eh%d
unsigned long state
设备状况
unsigned long base_addr
I/O基地址
unsigned int irq
中止号
首要设备办法有
int (*init)(struct net_device *dev)
初始化函数,该函数在register_netdev时被调用来完结对net_device结构的初始化
int (*open)(struct net_device *dev)
翻开接口。ifconfig激活时,接口将被翻开
int (*stop)(struct net_deivce *dev)
中止接口,ifconfig eth% down时调用
int (*hard_start_xmit)(struct sk_buf*skb,struct net_device *dev)
数据发送函数
int (*do_ioctl)(struct net_deive *dev,struct ifreq *ifr, int cmd)
处理特定于接口的ioctl指令(sock_ioctl)进行调用。
int (*set_mac_address)(struct net_device*dev, void *addr)
改动MAC地址的函数,需求硬件支撑该功用。
网络设备的注册
网络设备注册办法与字符驱动不同之处在于它没有主次设备号,并运用下面的函数注册
int register_netdev(struct net_deivce*dev)
网络设备的刊出
void unregister_netdev(struct net_device*dev)
3.网络数据包描绘(sk_buff)
Linux内核中每个网络数据包都由一个套接字缓冲区结构structsk_buff描绘,既每个sk_buff结构便是一个包,指向sk_buff的指针一般被称作skb
sk_buff中重要的数据成员
struct device *dev;处理该包得设备
__u32 sadd;r//IP元地址
__u32 daddr;//IP意图地址
__u32 raddr;//IP路由器地址
unsigned char *head;//分配空间的开端
unsigned char *data;//有用数据的开端
unsigned char *tail;//有用数据的完毕
unsigned char *end;//分配空间的完毕
unsigned long len;//有用数据的长度
sk_buff操作
struct sk_buff *alloc_skb(unsigned intlen, int priority)
分配一个sk_buff结构,供协议栈代码运用
struct sk_buff *dev_alloc_skb(unsignedint len)
分配一个sk_buff结构。供驱动代码运用
void kfree_skb(struct sk_buff *skb)
void dev_kfree_skb(struct sk_buff *skb)
开释sk_buff结构
unsigned char *skb_push(struct sk_buff*skb,int len)
将data指针向前移动len长度。并回来移动之后的值。用于向skb有用数据区域前端增加数据(包头)。
unsigned char *skb_put(struct sk_buff*skb, int len)
将taill指针向后移动len长度,并回来tail移动之前的值。用于向skb有用数据区域结尾增加数据。
4.驱动的完结
1).初始化(init)
设备勘探作业在init办法中进行,一般调用一个称之为probe办法的函数
初始化的首要作业时检测设备,装备和初始化硬件,最后向体系请求这些资源。此外填充该设备的dev结构,咱们调用内核供给的ether_setup办法来设置一些以太网默许的设置。
2)翻开(open)
open这个办法在网络设备驱动程序里是网络设备被激活时被调用(即设备状况由down变成up)
实际上很多在初始化的作业能够放到这里来做。比方说资源的请求,硬件的激活。假如dev->open回来非0,则硬件状况仍是down
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中的一些信息。
中止有可能是收到数据发生也可能是发送完结发生,中止处理程序要对中止类型进行判别,假如是收到数据中止则开端接纳数据,假如是发送完结中止,则处理发送完结后的一些操作,比方说重启发送行列。