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

linux下ip协议(V4)的实现(二)

阅读更多
这次主要介绍下forward和local delivery。

上次我们提到当ip_rcv_finish完成后后调用相关的发送函数ip_forward或者ip_local_deliver.这次就主要介绍这两个函数。

先来看forward。

forward一般由下面几部组成:

1 执行ip option
2 确定这个包能被forward
3 减小ttl,当ttl为0时,丢掉这个包
4 如果需要,则将这个包切片
5 发送包到输出网络设备

这里要注意,如果包由于一些原因,不能被forward,则必须发送ICMP消息到发送主机。

int ip_forward(struct sk_buff *skb)
{
	struct iphdr *iph;	/* Our header */
	struct rtable *rt;	/* Route we use */
	struct ip_options * opt	= &(IPCB(skb)->opt);
///gso相关设置
	if (skb_warn_if_lro(skb))
		goto drop;
///xfrm(ipsec)的相关检测
	if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb))
		goto drop;
///判断是否有Router_alter option(也就是保存发送端的ip),如果有的话,调用ip_call_ra_chain处理,当空间已满,则返回false,并继续处理。
	if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
		return NET_RX_SUCCESS;

///判断这个包是否是由本地主机的2层进行接受的。在2层设置帧的类型,当帧的目的地址就是本机2层地址的时候,skb->pkt_type设置为PCAKET_HOST.
	if (skb->pkt_type != PACKET_HOST)
		goto drop;

///由于是forward,因此我们不需要在意4层的校验。设置ip_summed为CHECKSUM_NONE。
	skb_forward_csum(skb);


	/*
	 *	According to the RFC, we must first decrease the TTL field. If
	 *	that reaches zero, we must reply an ICMP control message telling
	 *	that the packet's lifetime expired.
	 */
///ttl小于1,此时丢掉这个包
	if (ip_hdr(skb)->ttl <= 1)
		goto too_many_hops;

///ipsec的检测
	if (!xfrm4_route_forward(skb))
		goto drop;

///得到路由表
	rt = skb->rtable;

///判断是否是Strict源路由option。如果是的话,看源路由option所制定的路由能否和rt_gateway(下一跳)匹配。
	if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
		goto sr_failed;

///检测一些相关域。如果出错,则发送icmp,并丢弃这个包
	if (unlikely(skb->len > dst_mtu(&rt->u.dst) && !skb_is_gso(skb) &&
		     (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
		IP_INC_STATS(dev_net(rt->u.dst.dev), IPSTATS_MIB_FRAGFAILS);
		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
			  htonl(dst_mtu(&rt->u.dst)));
		goto drop;
	}

///由于我们将要修改这个skb的一些东西(在下面的ip_forward_finish中),因此我们需要复制一个拷贝(主要是防止skb共享)
	if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+rt->u.dst.header_len))
		goto drop;
	iph = ip_hdr(skb);

///减少ttl
	ip_decrease_ttl(iph);

///如果我们所找到的下一跳地址比请求的更好的话,源host现在将会收到一个ICMP REDIRESCT消息(只有当源host没有请求 source routing option时)
	if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb->sp)
		ip_rt_send_redirect(skb);

///QOS的优先级设置
	skb->priority = rt_tos2priority(iph->tos);

///最终返回netfilter的hook,这里我们还是暂时忽略netfilter,只关注ip_forward_finish.
	return NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev, rt->u.dst.dev,
		       ip_forward_finish);

sr_failed:
	/*
	 *	Strict routing permits no gatewaying
	 */
	 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0);
	 goto drop;

too_many_hops:
	/* Tell the sender its packet died... */
	IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_INHDRERRORS);
	icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
drop:
	kfree_skb(skb);
	return NET_RX_DROP;
}


下来看ip_forward_finish方法,它主要是用来处理一些剩下的options,并且ip_forward_options还会重新计算ip checksum,因为它会update一些ip头的域:

static int ip_forward_finish(struct sk_buff *skb)
{
	struct ip_options * opt	= &(IPCB(skb)->opt);

	IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);

	if (unlikely(opt->optlen))
		ip_forward_options(skb);
///最终返回dst_output,这个虚函数最终调用skb->dst_output,如果是单播则是ip_output,如果是多播则是ip_mc_output.而且切片(如果有需要)也会在这个函数进行).这里还有一个neighboring subsystem的概念,我们后面会讲到。
	return dst_output(skb);
}


来看ip_local_deliver函数:

int ip_local_deliver(struct sk_buff *skb)
{
	/*
	 *	Reassemble IP fragments.
	 */
///如果有切片,则开始组包。
	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
		if (ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER))
			return 0;
	}
///返回netfilter hook,最终会调用ip_local_deliver_finish.它最终会将数据包发送往4层。下一次我们会详细介绍这个函数。
	return NF_HOOK(PF_INET, NF_INET_LOCAL_IN, skb, skb->dev, NULL,
		       ip_local_deliver_finish);
}


这里我们可以看到一个对比,那就是forward时,不需要组包,这是因为local delivery必须把完整的包发送往4层,而forward,不需要经过4层,就直接把帧发送出去。

最后我们来看下ip_local_deliver_finish函数片段:


static int ip_local_deliver_finish(struct sk_buff *skb)
{
	struct net *net = dev_net(skb->dev);

	__skb_pull(skb, ip_hdrlen(skb));

	/* Point into the IP datagram, just past the header. */
	skb_reset_transport_header(skb);

	rcu_read_lock();
	{
		int protocol = ip_hdr(skb)->protocol;
		int hash, raw;
		struct net_protocol *ipprot;

	resubmit:
///对raw socket进行处理。
		raw = raw_local_deliver(skb, protocol);

		hash = protocol & (MAX_INET_PROTOS - 1);
		ipprot = rcu_dereference(inet_protos[hash]);
		if (ipprot != NULL) {
			int ret;

...................................................
///将数据包交给已注册的高层协议的处理函数。
			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;
}


分享到:
评论

相关推荐

    Linux协议栈实现分析

    对于Linux系统而言,其内核中的TCP/IP协议栈是实现网络通信的基础,它负责解析、处理并转发网络数据。本文将深入探讨Linux协议栈实现的细节,特别是与TCP/IP协议流程相关的部分。 首先,TCP/IP协议栈可以分为四层,...

    Linux协议栈的实现

    本文主要关注的是IP协议的实现,因为它是TCP/IP模型中最核心的部分之一。 #### 二、消息通讯简介 ##### 2.1 网络通讯路径 在Linux系统中,网络通讯路径涉及多个层次,从应用程序到物理层的数据传输过程中会经过多...

    Linux平台IP摄像头采集处理平台候选方案

    在构建Linux平台上的IP摄像头采集处理平台时,我们需要考虑多种技术方案来实现高效且可靠的视频流获取、处理和展示。以下是一些可行的解决方案及其详细说明: 1. USB摄像头采集处理方案: 利用Video4Linux接口是...

    Linux_picture.rar_linux_linux v4l2 _图片显示 Linux

    本教程将围绕Linux_v4l2接口来探讨如何在Linux环境下处理图像。 1. **Linux_v4l2接口**: Linux_v4l2是V4L(Video for Linux)的升级版,它提供了更强大的功能和更好的性能。V4L2接口为用户空间程序提供了与各种...

    Linux下基于MPEG4IP的实时授课同步技术和实现方法.pdf

    ### Linux下基于MPEG4IP的实时授课同步技术和实现方法 #### 概述 随着Linux在教育领域的广泛应用,开发基于Linux平台的网络实时授课系统变得尤为重要。本文介绍了一种利用MPEG4IP流媒体处理平台在Linux环境下实现...

    基于嵌入式Linux的无线视频监控系统设计与实现.pdf

    9. 通信工程:本文介绍了如何使用通信工程技术实现视频服务器信号传输,该系统使用TCP/IP协议将视频数据传输到客户端。 10. 软件工程:本文介绍了如何使用软件工程技术实现视频监控系统,该系统使用Linux内核和V4L2...

    嵌入式linux下多线程视频监控的设计和实现

    流媒体服务器则负责将这些数据通过TCP/IP协议在网络上传输,实现多用户访问。 V4L2是Linux下的一套视频设备驱动接口,提供了一种统一的方式来控制不同硬件的视频设备,简化了开发过程。使用V4L2接口,可以进行诸如...

    linux下视频监控

    本项目主要使用了Linux的Video for Linux Two(V4L2)框架来采集视频源,然后通过QT进行图像处理和TCP/IP协议传输,最终在WEB端展示,实现远程监控的功能。 1. **Video for Linux Two (V4L2)**: V4L2是Linux内核中...

    ok2440 linux部分第四版v4

    7. **网络通信**:讲述如何配置网络接口,包括以太网控制器驱动和TCP/IP协议栈的配置,实现嵌入式设备的网络功能。 8. **应用程序开发**:介绍如何在Linux环境下进行C/C++编程,开发针对S3C2440的应用程序,以及...

    v4l2onvif-master_ONVIF_ONVIFSERVER_onvifserver_v4l2onvif_

    标题 "v4l2onvif-master_ONVIF_ONVIFSERVER_onvifserver_v4l2onvif_" 暗示这是一个关于ONVIF协议实现的项目,特别是与Linux环境下的服务器和客户端相关。ONVIF是Open Network Video Interface Forum(开放网络视频...

    webcam_v4l2_x264

    总的来说,webcam_v4l2_x264项目是一个实用的示例,展示了如何在Linux环境下利用V4L2接口和x264编码器实现摄像头视频的捕捉、压缩和网络传输,以及在远程端进行解码和播放。这为开发自己的视频流应用或者研究相关...

    linux+QT下基于RTP协议的实时视频传输客户端和服务端

    总的来说,这个项目涉及到了Linux系统编程、QT图形界面开发、RTP协议的实现、V4L2接口的使用以及OpenCV的人脸识别技术,是一个综合性的实时视频传输解决方案。开发这样的系统有助于提升开发者在跨平台实时多媒体应用...

    嵌入式linux下多线程视频监控的设计和实现.pdf

    通过TCP/IP协议,它可以将视频流发送到网络,使用户能够通过监控终端(如Web浏览器)访问视频监控画面。 6. **硬件平台搭建**:系统硬件通常包括处理器(如S3C2440A)、存储器(如NAND/SDRAM/NOR Flash)以及视频...

    国嵌最新版网络摄像头(已加入v4l2)

    7. 网络传输:如果摄像头用于网络视频传输,需要了解TCP/IP协议和相关网络编程知识。 总结,这个项目是关于在网络摄像头应用中整合v4l2框架,以提升其在Linux环境下的性能和兼容性。这涵盖了从底层硬件驱动到上层...

    EDNS基于linux内核模块的实现

    总的来说,EDNS的内核实现是一项复杂的工作,涉及到对Linux内核代码的深入了解,以及对DNS协议和网络安全的深刻理解。通过这种方式增强DNS功能,可以提高系统的效率和安全性,但同时也需要谨慎处理潜在的负面影响。

    一种改进的Linux下的IPv4_IPv6转换网关.pdf

    NAT-PT技术是IPv4与IPv6互通的重要手段,它通过改变IP地址和端口号来实现不同协议间的转换。DNS-ALG则是在DNS查询过程中帮助处理NAT-PT转换的组件,确保通信的正确性。 传统方案存在的问题是,当IPv6网络扩大、通信...

    v4l2+Qt+百度语音

    2. **服务器端的网络传输**:使用TCP/IP协议,通过QTcpServer监听客户端连接,当有连接建立时,将视频流和语音数据实时发送给客户端。 3. **客户端**:使用QTcpSocket建立与服务器的连接,接收视频流并解码显示,...

    基于嵌入式linux的视频采集系统设计

    这里主要采用H.263编码器对视频数据进行压缩,再通过TCP/IP协议栈中的RTP(Real-time Transport Protocol)进行传输。 ##### 1. H.263视频编码 H.263是一种适用于低带宽环境下的视频编码标准,特别适合嵌入式系统中...

    Linux下机器人数字化图像采集系统软件设计.pdf

    可以使用TCP/IP协议栈,结合socket编程,实现实时图像数据的封装和发送。 3. 性能优化与调试 3.1 性能优化:为了提高图像采集速度和处理效率,可以考虑硬件加速、多线程处理、内存管理优化等方法。 3.2 调试与...

    Linux_Video.rar_linux 对讲_linux视频_对讲程序 linux_视频对讲开发

    在本项目“Linux_Video.rar”中,开发者显然利用V4L2库来实现了一套Linux下的视频对讲解决方案。下面将详细介绍V4L2以及视频对讲程序开发的相关知识点。 1. V4L2简介: V4L2是Linux内核的第二代视频接口,它提供了...

Global site tag (gtag.js) - Google Analytics