首页 > 代码库 > 网络体系结构

网络体系结构

协议模型


协议栈底部是链路层,链路层提供对物理层访问的设备驱动程序,物理层一般就是各种介质,例如串口链路或以太网设备。链路层上面是网络层,负责接收、发送或转发数据包。网络层的上一层为传输层,负责数据传输和数据控制,提供端到端数据交换机制。最上层是应用层,它通常是语义层,能够理解要传输的数据。

网络架构

网络协议栈顶部是系统调用接口,为用户空间中的应用程序提供一种访问内核网络子系统的接口。下面是一个协议无关层,它提供了一种通用方法来使用传输层协议。然后是传输层的具体协议,包括TCP、UDP。在传输层下面是网络层。然后是邻居子系统,在邻居子系统存在的目标才是当前可以直接访问的。再下面是网络层设备接口,提供了与各个设备驱动程序通信的通信接口。最低层是设备驱动程序。


系统调用接口

网络子系统提供了两种调用接口给用户进程。

通过特有的网络调用接口进入内核,在sys_socketcall()中会根据网络系统调用号调用具体功能

另一种系统调用接口是通过普通文件操作来访问网络子系统。

协议无关接口

通过网络协议栈通信都需要对套接口进行操作。套接口层是一个协议无关的接口。它提供一组接口来支持各种协议。

Linux中用socket结构描述套接口,代表一条通信链路的一端,用来存储与该链路有关的所有信息。这些信息包括所使用的协议、协议的状态信息、到达的连接队列、数据缓存和可选标志等。其中最关键的成员是sk和ops,前者指向与该套接口相关的传输控制块,后者指向特定传输协议的操作集。

struct socket {
	socket_state		state;
	unsigned long		flags;
	struct proto_ops	*ops;
	struct fasync_struct	*fasync_list;
	struct file		*file;
	struct sock		*sk;
	wait_queue_head_t	wait;
	short			type;
	unsigned char		passcred;
};

传输层协议

套接口的sk字段指向与该套接口相关的传输控制块,传输层使能传输控制块存放套接口所需的信息。传输控制块按协议而异,TCP传输控制块,UDP传输控制块,RAW传输控制块。分别对应tcp_sock、udp_sock、raw_sock

套接口缓存

网络子系统中用来存储数据的缓冲区叫做套接口缓存,简称SKB。该缓存区能够处理可变长数据,即能够很容易地在数据区头尾添加和移除数据,且尽量避免数据的复制

struct sk_buff
{
	/* These two members must be first. */
	struct sk_buff		*next;
	struct sk_buff		*prev;

	struct sk_buff_head	*list;
	struct sock		*sk;
	struct timeval		stamp;
	struct net_device	*dev;
	struct net_device	*input_dev;
	struct net_device	*real_dev;

	union {
		struct tcphdr	*th;
		struct udphdr	*uh;
		struct icmphdr	*icmph;
		struct igmphdr	*igmph;
		struct iphdr	*ipiph;
		struct ipv6hdr	*ipv6h;
		unsigned char	*raw;
	} h;

	union {
		struct iphdr	*iph;
		struct ipv6hdr	*ipv6h;
		struct arphdr	*arph;
		unsigned char	*raw;
	} nh;

	union {
	  	unsigned char 	*raw;
	} mac;

	struct  dst_entry	*dst;
	struct	sec_path	*sp;

	/*
	 * This is the control buffer. It is free to use for every
	 * layer. Please put your private variables there. If you
	 * want to keep them across layers you have to do a skb_clone()
	 * first. This is owned by whoever has the skb queued ATM.
	 */
	char			cb[40];

	unsigned int		len,
				data_len,
				mac_len,
				csum;
	unsigned char		local_df,
				cloned,
				pkt_type,
				ip_summed;
	__u32			priority;
	unsigned short		protocol,
				security;

	void			(*destructor)(struct sk_buff *skb);
#ifdef CONFIG_NETFILTER
        unsigned long		nfmark;
	__u32			nfcache;
	__u32			nfctinfo;
	struct nf_conntrack	*nfct;
#ifdef CONFIG_NETFILTER_DEBUG
        unsigned int		nf_debug;
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
	struct nf_bridge_info	*nf_bridge;
#endif
#endif /* CONFIG_NETFILTER */
#if defined(CONFIG_HIPPI)
	union {
		__u32		ifield;
	} private;
#endif
#ifdef CONFIG_NET_SCHED
       __u32			tc_index;        /* traffic control index */
#ifdef CONFIG_NET_CLS_ACT
	__u32           tc_verd;               /* traffic control verdict */
	__u32           tc_classid;            /* traffic control classid */
#endif

#endif


	/* These elements must be at the end, see alloc_skb() for details.  */
	unsigned int		truesize;
	atomic_t		users;
	unsigned char		*head,
				*data,
				*tail,
				*end;
}
SKB主要用于在网络驱动程序和应用程序之间传递、复制数据包。当应用程序要发送一个数据包时,数据通过系统调用提交到内核,系统会分配一个SKB来存储数据,然后往下层传递,在传输给网络驱动后才将其释放。当网络设备接收到数据包后,同样要分配一个SKB来存储数据,然后往上传递,最终在数据复制到应用程序后释放。

设备无关接口

网络协议栈底部是一个与硬件设备无关的接口层,它将网路层的不同协议与各种网络设备连接在一起。设备无关接口提供了一组通用函数供底层网络设备驱动程序和上层协议栈调用,这样当输出数据时协议栈不必关心底层的网络设备。而当输入数据时网络设备驱动程序同样也不必关心上层的协议栈。

协议栈向设备发送数据包时都需要调用dev_queue_xmit()。该函数对SKB进行排队,最终由底层设备驱动程序进行传输。

而接收报文通常是调用netif_rx()实现的。当底层设备驱动程序接收到一个报文时,就会通过调用netif_rx()将报文的SKB上传至网络层。

设备驱动程序

网络设备由net_device结构来描述,每个网络设备都有一个对应的实例,然后调用register_netdevice()注册到系统中,注册过的网络设备可通过unregister_netdevice()注销。

net_device结构中包含了一个名为hard_start_xmit的接口,通常在初始化网络设备时设置,实现向该网络设备输出数据包。在接收数据包时,支持NAPI驱动程序通常需实现net_device结构的poll接口。