`
simohayha
  • 浏览: 1386164 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

ip层和4层的接口实现分析

阅读更多
首先来看一下基于3层的ipv4以及ipv6实现的一些4层的协议:





这里要注意并没有IGMPV6,这是因为在ipv6中,它是作为iCMPv6的一部分实现的.


首先我们要知道输入数据包的ip头中的protocol域标识了,将要传递的4层协议.


我们这里主要介绍的是ip数据包从3层传递到4层的接口(也就是输入帧接口).而输出帧的处理,我前面的blog都已经有介绍,想了解的话,可以去看前面的blog.

先来看主要的数据结构,然后我们会分析ip_local_deliver_finish函数(也就是3层处理的出口函数).

在内核中,每一个4层协议都是一个net_protocol结构体,而内核会在启动的时候将所有的4层协议都注册到一个数组inet_protos中,然后根据数据包的ip头来得到相应的handle函数:

struct net_protocol {
///协议的处理函数,也就是将要处理输入数据报的4层协议的处理函数.
	int			(*handler)(struct sk_buff *skb);
///协议的错误处理函数.
	void			(*err_handler)(struct sk_buff *skb, u32 info);
///gso相关的两个函数.
	int			(*gso_send_check)(struct sk_buff *skb);
	struct sk_buff	       *(*gso_segment)(struct sk_buff *skb,
					       int features);

///主要是被ipsec所使用的两个域
	unsigned int		no_policy:1,
				netns_ok:1;
};



L4的协议都是在linux/in.h这个文件中,都是以IPPROTO开头的一些宏.由于ip头中的4层协议域是8位,因此4层协议的最大数值也就是255.而在内核中,255是raw ip, IPPPROTO_RAW:

enum {
  IPPROTO_IP = 0,		/* Dummy protocol for TCP		*/
  IPPROTO_ICMP = 1,		/* Internet Control Message Protocol	*/
  IPPROTO_IGMP = 2,		/* Internet Group Management Protocol	*/
  IPPROTO_IPIP = 4,		/* IPIP tunnels (older KA9Q tunnels use 94) */
  IPPROTO_TCP = 6,		/* Transmission Control Protocol	*/
  IPPROTO_EGP = 8,		/* Exterior Gateway Protocol		*/
  IPPROTO_PUP = 12,		/* PUP protocol				*/
  IPPROTO_UDP = 17,		/* User Datagram Protocol		*/
  IPPROTO_IDP = 22,		/* XNS IDP protocol			*/
  IPPROTO_DCCP = 33,		/* Datagram Congestion Control Protocol */
  IPPROTO_RSVP = 46,		/* RSVP protocol			*/
  IPPROTO_GRE = 47,		/* Cisco GRE tunnels (rfc 1701,1702)	*/

  IPPROTO_IPV6	 = 41,		/* IPv6-in-IPv4 tunnelling		*/

  IPPROTO_ESP = 50,            /* Encapsulation Security Payload protocol */
  IPPROTO_AH = 51,             /* Authentication Header protocol       */
  IPPROTO_BEETPH = 94,	       /* IP option pseudo header for BEET */
  IPPROTO_PIM    = 103,		/* Protocol Independent Multicast	*/

  IPPROTO_COMP   = 108,                /* Compression Header protocol */
  IPPROTO_SCTP   = 132,		/* Stream Control Transport Protocol	*/
  IPPROTO_UDPLITE = 136,	/* UDP-Lite (RFC 3828)			*/

  IPPROTO_RAW	 = 255,		/* Raw IP packets			*/
  IPPROTO_MAX
};



这里要上面列出的协议,并不是所有的都在内核态handle的,其中一些经常在用户态handle的例如(IPPROTO_RSVP).


内核是通过inet_add_protocol来添加协议到inet_protos数组中的,相应的还有一个删除方法,我们先来看inet_protos的结构:





这里要注意的就是读写inet_protos时,使用的是自旋锁,而只读时,使用的是RCU(Read-Copy Update).


然后来看inet_add_protocol的源码:



struct net_protocol *inet_protos[MAX_INET_PROTOS] ____cacheline_aligned_in_smp;


///这里只是举两个例子,tcp和udp的协议注册函数.我们这次暂时就不分析tcp和udp的处理函数了(我会在3层结束后,分析4层源码)
static struct net_protocol tcp_protocol = {
	.handler =	tcp_v4_rcv,
	.err_handler =	tcp_v4_err,
	.gso_send_check = tcp_v4_gso_send_check,
	.gso_segment =	tcp_tso_segment,
	.no_policy =	1,
	.netns_ok =	1,
};

static struct net_protocol udp_protocol = {
	.handler =	udp_rcv,
	.err_handler =	udp_err,
	.no_policy =	1,
	.netns_ok =	1,
};


int inet_add_protocol(struct net_protocol *prot, unsigned char protocol)
{
	int hash, ret;

///计算当前协议在数组中的slot.
	hash = protocol & (MAX_INET_PROTOS - 1);

///使用自旋锁.
	spin_lock_bh(&inet_proto_lock);
	if (inet_protos[hash]) {
		ret = -1;
	} else {
///将相应的prot添加到数组
		inet_protos[hash] = prot;
		ret = 0;
	}
	spin_unlock_bh(&inet_proto_lock);
	return ret;
}





然后这些协议的注册都是在内核boot的时候在inet_init中初始化的,下面就是inet_init的代码片段.:

static int __init inet_init(void)
{
	...........................................
	/*
	 *	Add all the base protocols.
	 */

	if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
		printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");
	if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
		printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");
	if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
		printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
#ifdef CONFIG_IP_MULTICAST
	if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)
		printk(KERN_CRIT "inet_init: Cannot add IGMP protocol\n");
#endif

..................................
}


知道协议如何注册之后,我们来分析ip_local_deliver_finish函数,来看3层是如何将数据包发送到4层的.

1 我们知道linux支持raw数据包的发送,因此在这里会对raw socket进行了特殊处理,它会clone一份数据包然后传递给相应的raw处理函数,然后再继续后面的处理.

2 ipsec.这时还需要加上相应的ipsec头,然后再传给4层处理.看下面的图:







static int ip_local_deliver_finish(struct sk_buff *skb)
{

///取出相应的net信息.
	struct net *net = dev_net(skb->dev);
///下面两个主要是调整data指针,使data指针指向4层的数据开始处.
	__skb_pull(skb, ip_hdrlen(skb));
	skb_reset_transport_header(skb);

///加rcu锁.
	rcu_read_lock();
	{
///取出ip头中的协议.
		int protocol = ip_hdr(skb)->protocol;
		int hash, raw;
		struct net_protocol *ipprot;

	resubmit:
///得到raw socket, 如果不是raw socket,则返回0.
		raw = raw_local_deliver(skb, protocol);

///计算4层协议的slot.
		hash = protocol & (MAX_INET_PROTOS - 1);
///rcu读取相应的协议处理结构.
		ipprot = rcu_dereference(inet_protos[hash]);
///主要是ipprot是否有被当前主机注册.
		if (ipprot != NULL && (net == &init_net || ipprot->netns_ok)) {
			int ret;

///判断ipsec,并进行相关处理.
			if (!ipprot->no_policy) {
				if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
					kfree_skb(skb);
					goto out;
				}
				nf_reset(skb);
			}
///调用handler,进入相应的4层协议的处理.
			ret = ipprot->handler(skb);
			if (ret < 0) {
				protocol = -ret;
				goto resubmit;
			}
			IP_INC_STATS_BH(net, IPSTATS_MIB_INDELIVERS);
		}
................................................
 out:
	rcu_read_unlock();

	return 0;
}


最后来看一下raw socket的处理,通过上面我们知道,会调用raw_local_deliver来进行raw socket的相关处理(如果没有raw socket,则会直接返回):


当应用程序使用raw ip socket,他只需要攒递给内核协议id(4层的协议),以及目的地址.因此这里存取sock的hash表使用的key就是4层协议id.

///相应的hash表,保存raw socket.
struct raw_hashinfo {
	rwlock_t lock;
	struct hlist_head ht[RAW_HTABLE_SIZE];
};

static struct raw_hashinfo raw_v4_hashinfo = {
	.lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
};



int raw_local_deliver(struct sk_buff *skb, int protocol)
{
	int hash;
	struct sock *raw_sk;
///通过协议计算hash值(使用4层协议id).
	hash = protocol & (RAW_HTABLE_SIZE - 1);
///得到相应的raw_sk.
	raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);

	/* If there maybe a raw socket we must check - if not we
	 * don't care less
	 */
///交给raw socket的处理函数,raw_v4_input中会clone一个skb,然后交给最后的raw_rev函数去处理最终的数据包.
	if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash))
		raw_sk = NULL;

	return raw_sk != NULL;

}


  • 大小: 13 KB
  • 大小: 45.1 KB
  • 大小: 21.1 KB
分享到:
评论

相关推荐

    用户层和传输层协议分析指导书

    实验原理: 1. 应用层协议 应用层协议(application layer protocol)定义了运行在不同端系统上的应用程序进程如何相互传递报文。 1)域名系统(Domain Name System,DNS):用于实现...4、对传输过程和数据报文进行协议分析

    TCP/IP技术大全

    第4章 IP网络中的名字和地址 29 4.1 IP寻址 29 4.1.1 二进制和十进制数 30 4.1.2 IPv4地址格式 30 4.2 子网的出现 34 4.2.1 分子网 35 4.2.2 可变长子网掩码(VLSM) 37 4.3 无类域前路由(CIDR) 38 4.3.1 无类地址 38 ...

    TCP/IP教程TCP/IP基础

    第4章 IP网络中的名字和地址 29 4.1 IP寻址 29 4.1.1 二进制和十进制数 30 4.1.2 IPv4地址格式 30 4.2 子网的出现 34 4.2.1 分子网 35 4.2.2 可变长子网掩码(VLSM) 37 4.3 无类域前路由(CIDR) 38 4.3.1 无类地址 38 ...

    TCP-IP技术大全

    第4章 IP网络中的名字和地址 29 4.1 IP寻址 29 4.1.1 二进制和十进制数 30 4.1.2 IPv4地址格式 30 4.2 子网的出现 34 4.2.1 分子网 35 4.2.2 可变长子网掩码(VLSM) 37 4.3 无类域前路由(CIDR) 38 4.3.1 无类地址 38 ...

    TCP/IP技术大全(中文PDF非扫描版)

    第4章 IP网络中的名字和地址 29 4.1 IP寻址 29 4.1.1 二进制和十进制数 30 4.1.2 IPv4地址格式 30 4.2 子网的出现 34 4.2.1 分子网 35 4.2.2 可变长子网掩码(VLSM) 37 4.3 无类域前路由(CIDR) 38 4.3.1 无类地址 38 ...

    TCP\IP网络互联技术

    重点放在客户—服务器机制上,介绍了客户-服务器机制和应用程序用于网络通信的套接字接口,分析了分布式程序的客户端和服务器两部分的算法,讨论了客户端和服务器的设计及遵循的模式。本书在并发处理上也花费了相当...

    TCP/IP设计的解决方案

    通过优化设计清晰的TCP/IP和应用层接口、防止多余的内存拷贝和实现数据包整序重发及窗口控制,分析在嵌入式系统上实现TCP/IP的速度、程序大小、内存大小以及编译嚣等特点,并针对这些特,最提出实现TCP/IP的技巧...

    TCP/IP详解

    第4章 IP网络中的名字和地址 29 4.1 IP寻址 29 4.1.1 二进制和十进制数 30 4.1.2 IPv4地址格式 30 4.2 子网的出现 34 4.2.1 分子网 35 4.2.2 可变长子网掩码(VLSM) 37 4.3 无类域前路由(CIDR) 38 4.3.1 无类地址 38 ...

    Delphi网络通信协议分析与应用实现pdf清晰

    2.1.5 关于IP地址和实际的地址的区别 2.2 获取子网掩码 2.2.1 Windows NT系统中获取子网掩码 2.2.2 Window 9x系统中获取子网掩码 2.3 获取计算机名 2.3.1 获取和设置本机主机名 2.3.2 获取远程主机名称 2.4 ...

    基于 Java的 SSFNet 的框架分析和应用扩展

    SSFNet是一个用于Internet网络及其协议的仿真软件,它采用Java语言来实现内核和组件 的编码,它的每一个组件对应一个相应的协议。由于Java语言的面向对象...最后给出了SSFNet中基于映射机制的来实现对IP层仿真的扩展。

    毕业设计4G移动通信技术的分析与研究.doc

    物理网络层与中间环境层及其应用环境之间的" "接口是开放的,使发展和提供新的服务变得更容易,提供无缝高数据率的无" "线服务,并运行于多个频带,这一服务能自适应于多个无线标准及多模终。" "未来无线多媒体业务...

    嵌入式系统/ARM技术中的基于嵌入式TCP/IP软件体系结构的优化设计与实现

    摘要: 本文提出一种基于嵌入式TCP/IP软件体系结构的优化设计和解决方案,通过分析在嵌入式系统上实现TCP/IP的速度、程序结构、内存需求等特点,优化设计了清晰的TCP/IP和应用层接口、防止多余的内存拷贝和实现数据包整...

    国家标准osi模型与组建

     在TCP/IP参考模型中,去掉了OSI参考模型中的会话层和表示层(这两层的功能被合并到应用层实现)。同时将OSI参考模型中的数据链路层和物理层合并为主机到网络层。下面,分别介绍各层的主要功能。  1、主机到网络层...

    WAP协议栈总体设计及其实现技术.pdf

    灵活性主要表现在各层对应单独的模块且独立性强,而各模块为其上层或具体应用可提供统一的接口,可以选择不同的模块进行组合构成不同的应用·独立的通信处理模块使层间通信易于实现·采用多线程技术,提高了系统并行...

    通信与网络中的嵌入式TCP/IP的优化设计与硬件实现

    通过优化设计清晰的TCP/IP和应用层接口、防止多余的内存拷贝和实现数据包整序重发及窗口控制,分析在嵌入式系统上实现TCP/IP的速度、程序大小、内存大小以及编译嚣等特点,并针对这些特,最提出实现TCP/IP的技巧...

    LWIP中文手册

    本文结构如下编排:第2,3和4部分对lwIP栈作一个概述,第5部分叙述操作系统模拟层, 第6部分叙述缓存和存储管理。第7部分介绍lwIP抽象的网络接口,第8,9,和10部分叙述IP, UDP,和TCP协议的实现。第11和12部分叙述...

    校园网IPv6方案的设计与实现.doc

    校园网IPv6方案的设计与实现 1绪 论 2 1.1什么是IPv6 2 1.2IPv6和IPv4的区别 2 1.3IPv6的几种关键技术 2 1 路由转发技术 3 2 应用支持IPv6的技术 3 3 IPv6过渡技术 3 2校园网应用特点及需求分析 4 2.1校园网应用...

    利用Socket实现双机通信(计算机网络课程设计).doc

    开发组件是供程序员在w indows环境下开发网络应用程序使用的,它包括应用程序接口库函数、头文件和实现的 文档,其中最主要的是WINSOCK.H运行组件是以动态链接库(DlL)来实现socket接口的。 文件名为WINSOCK.DLL应用...

    计算机网络常见问题解答

    问题4-25:有人将ARP列入网络接口层,即认为ARP不在IP层,这样对吗? 问题4-26:一个主机要向另一个主机发送IP数据报。是否使用ARP就可以得到该目的主机的硬件地址,然后直接用这个硬件地址将IP数据报发送给目的主机...

Global site tag (gtag.js) - Google Analytics