分类: LINUX
2009-03-18 11:15:12
网络框架表
BSD socket层socket{} |
数据结构proto_sw{}分别对应inet_dgram_ops和inet_stream_ops全局变量 |
数据传输时使用msghdr{}数据结构, |
Sock层使用sock{}数据结构 |
数据结构proto{}分别对应udp_prot和tcp_prot全局变量 |
使用sk_buff{}来存储数据 |
使用inet_protosw{}数据结构的来管理proto_sw{}和proto{}类型的变量, inet_protosw{}有全局变量inetsw_array[]和inetsw[MAX_SOCK],其组织结构如下所示,而在函数inet_create()创建socket{}和sock{}数据结构变量时,需要从上面的inetsw[]中检索其对应的proto_sw{}和proto{}数据结构。 | ||
net_protocol{}数据结构是L4层的协议数据结构,该数据结构中包含了数据接收过程,udp_protocol, icmp_protocol, tcp_protocol, 并使用数组inet_protos[]来组织上面的几个全局变量 | ||
IP层处理,L3层,ip_rcv()进行分包 | ||
数据结构packet_type{}对应L2层处理,ip_packet_type和arp_packet_type分别是对应的变量,使用全局数组ptype_base[]和链表ptype_all组织该数组,具体组织方式参考文档下面的说明 | ||
使用数据结构softnet_data{}来管理从网卡驱动接收到的数据帧。 | ||
数据结构net_device{},使用数组dev_base[]来组织对应的变量,对应操作函数为register_netdev(), dev_get_by_name(),dev_get_by_index()等 |
层说明
linux的网络实现是独立于特定的协议的,和传输层协议(tcp,udp)、网络层协议(ip)、网络适配器层(network adpter protocol,例如:ethernet,token ring,etc)。
关键在于两个文件include/linux/net.h, include/net/protocol.h。定义了各种数据结构
BSD socket层对应的表示一个连接的数据结构是socket{}数据结构,在socket数据结构中有一个指针proto_ops,该指针指向数据结构proto_ops{},其中有每个socket对应的操作函数,包括send, recv, bind, connect等。在该层中使用msghdr{}数据结构来表示数据。
全局变量static struct net_proto_family *net_families[NPROTO];该全局变量对应的数据结构中仅有一个create()函数指针比较有用,inet类型socket对应全局变量inet_family_ops, 对应函数inet_create();packet类型的socket对应全局变量packet_family_ops, 对应函数packet_create()。
在应用程序创建一个socket时,在函数sock_create()中,会使用该全局数组net_families[NPROTO]调用其socket类型对应的create()函数。
另外socket{}数据结构对应的操作函数集数据结构proto_ops{}对应的变量也要静态定义,inet类型的stream和dgram数据报分别对应操作函数集变量inet_stream_ops,inet_dgram_ops。事实上,因为我们关注的stream类型的socket就特指tcp socket,而dgram类型的socket就特指udp socket。
层的说明
Inet Socket层,即脱离socket与应用程序接口,查找其与L4通信协议的接口。该层对应的数据结构是sock{}数据结构,数据结构sock_common{}包含在其中,而数据结构inet_sock{}又内嵌了sock{}数据结构;inet_sock->proto指针指向proto{}数据结构,在proto{}数据结构中包含了进行操作的函数指针。对应的数据包采用了sk_buff{}数据结构来表示。
此时proto{}数据结构也要使用静态全局变量来定义,其对应的变量是udp_prot, tcp_prot, raw_prot。
全局变量组织关系
层和sock层的操作函数的整合
数据结构struct inet_protosw{}是某些传输层协议所提供的服务类型,例如:SOCK_STREAM对应可靠数据流服务,SOCK_DGRAM对应不可靠数据报文服务,SOCK_RAW对应原始IP层服务。
在数据结构inet_protosw{}中既有struct proto{}的指针,也有struct proto_ops{}数据结构的指针。
对应静态全局变量static struct inet_protosw inetsw_array[] ={}
该静态全局变量静态定义了三种socket类型:SOCK_STREAM、SOCK_DGRAM、SOCK_RAW。
针对ipv4的话实际上是一一对应的,SOCK_STREAM对应tcp, SOCK_DGRAM对应udp,SOCK_RAW对应raw ip。
使用inet_protosw{}数据结构对proto{}和proto_ops{}类型的变量进行组织。在此有两个全局数组。
static struct list_head inetsw[SOCK_MAX];
static struct inet_protosw inetsw_array[]={}
数组链表inetsw[SOCK_MAX]相当于把inetsw_array[]中的表项做了一个重新整理,下面是对其关系的说明。
层接收数据结构net_protocol{}的管理
类型net_protocol的作用是提供一个本协议的接收函数,网络层收到数据报后,根据IP首部中的协议字段确定是那一个协议的数据报,然后再到全局变量inet_protos中找到这个接收函数。
在文件include/net/protocol.h中定义该结构,在文件net/ipv4/protocol.c定义下面的全局变量,所有的传输层的协议TCP, UDP, ICMP, IGMP都要在其中注册下面的数组中。
struct net_protocol *inet_protos[MAX_INET_PROTOS];
#define MAX_INET_PROTOS 256
使用函数inet_add_protocol把协议protocol的编号加到hash表inet_protos中,
使用inet_del_protocol从hash表inet_protos删除某个协议。
在文件net/ipv4/af_inet.c中静态定义了协议变量tcp_protocol, udp_protocol, igmp_protocol, icmp_protocol。
层发送和接收数据报
ip层负责把L4层协议要发送的数据发送到下面一层,也负责把从L2层接收到的数据送达相应L4层协议的接收函数。关于IP层的描述,参照下一篇文档,linux IP层解析。
数据结构的管理
该数据结构是用于在协议栈与网络设备之间构筑一个数据传递的桥梁。它根据网卡收到的数据帧类型调用相应的协议。
有两个全局的变量:
static struct list_head ptype_base[16];
static struct list_head ptype_all;
可以调用函数dev_add_pack()可把packet_type{}类型变量添加到hash表中.
在接收数据时netif_receive_skb()函数遍历ptype_base链表,调用其中的每个rcv函数,并传入skb结构。
在文件net/ipv4/af_inet.c中静态定义了变量ip_packet_type,用来表示ip包结构
在文件net/ipv4/arp.c中静态定义了变量arp_packet_type,用来表示arp包结构
类型的变量的组织
数据结构管理从网卡接收数据
每个CPU对应一个,它是一个结构体struct softnet_data类型,
struct softnet_data
{
struct net_device *output_queue;
struct sk_buff_head input_pkt_queue;
struct list_head poll_list;
struct sk_buff *completion_queue;
struct net_device backlog_dev;
};
成员input_pkt_queue是core层次的接收数据队列。结构体struct sk_buff_head的成员qlen记录接收队列的长度,内核中对接收队列的长度有一个上限限制mynetdev_max_backlog,其值定义为1000。
在Linux内核中,用结构体struct net_device{}代表一个网络设备接口,内核函数register_netdev()用于向内核注册一个网络设备接口。下面看几个网络设备注册相关的数据结构。
dev_base是一个struct net_device的全局指针,它指向的是一个包含当前系统中所有网络设备接口的链表,每次调用register_netdev()注册一个新的网络设备接口时,都会在这个链表的尾部新添加一项。
dev_name_head是一个list数组,它实际上是一个哈希表,系统中所有的的网络设备都以它们的名字作为哈希键值放入这个哈希表,以提供诸如dev_get_by_name()这样的接口,使得可以通过设备名找到设备。
dev_index_head也是一个list数组形式的哈希表,系统中的所有网络设备在注册时都会被分配给一个索引号,它是按照设备注册的顺序递增的一个值。所有的网络设备都以它们分配的索引号作为哈希键值放入这个哈希表,以提供诸如dev_get_by_index()这样的接口,使得可以通过设备索引号找到设备。
对net_device{}数据结构的组织
netdev_chain是一个struct notifier_block的全局链表,当一个网络设备接口被注册或状态发生变化时,需要调用这个链表中每一项中的成员函数,以通知相关模块,设备发生了变化。如果某一模块需要得到网络设备发生变化的通知,它只需要定义一个struct notifier_block,提供一个通知回调函数即可。所以网络设备注册接下来要调用notifier_call_chain,通知所有相关的模块,有一个新的网络设备接口被注册进来了。