- 浏览: 1386809 次
- 性别:
- 来自: 火星
文章分类
最新评论
-
aidd:
内核处理time_wait状态详解 -
ahtest:
赞一下~~
一个简单的ruby Metaprogram的例子 -
itiProCareer:
简直胡说八道,误人子弟啊。。。。谁告诉你 Ruby 1.9 ...
ruby中的类变量与类实例变量 -
dear531:
还得补充一句,惊群了之后,数据打印显示,只有一个子线程继续接受 ...
linux已经不存在惊群现象 -
dear531:
我用select试验了,用的ubuntu12.10,内核3.5 ...
linux已经不存在惊群现象
这次主要介绍下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消息到发送主机。
下来看ip_forward_finish方法,它主要是用来处理一些剩下的options,并且ip_forward_options还会重新计算ip checksum,因为它会update一些ip头的域:
来看ip_local_deliver函数:
这里我们可以看到一个对比,那就是forward时,不需要组包,这是因为local delivery必须把完整的包发送往4层,而forward,不需要经过4层,就直接把帧发送出去。
最后我们来看下ip_local_deliver_finish函数片段:
上次我们提到当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; }
发表评论
-
Receive packet steering patch详解
2010-07-25 16:46 11959Receive packet steering简称rp ... -
内核中拥塞窗口初始值对http性能的影响分析
2010-07-11 00:20 9626这个是google的人提出的 ... -
linux 内核tcp拥塞处理(一)
2010-03-12 16:17 9493这次我们来分析tcp的拥塞控制,我们要知道协议栈都是很保守的, ... -
内核tcp协议栈SACK的处理
2010-01-24 21:13 12073上一篇处理ack的blog中我 ... -
内核tcp的ack的处理
2010-01-17 03:06 11070我们来看tcp输入对于ack,段的处理。 先是ack的处理, ... -
内核处理time_wait状态详解
2010-01-10 17:39 6707这次来详细看内核的time_wait状态的实现,在前面介绍定时 ... -
tcp协议栈处理各种事件的分析
2009-12-30 01:29 13563首先我们来看socket如何将一些状态的变化通知给对应的进程, ... -
linux内核sk_buff的结构分析
2009-12-25 00:42 47815我看的内核版本是2.6.32. 在内核中sk_buff表示一 ... -
tcp的输入段的处理
2009-12-18 00:56 8271tcp是全双工的协议,因此每一端都会有流控。一个tcp段有可能 ... -
内核协议栈tcp层的内存管理
2009-11-28 17:13 11921我们先来看tcp内存管理相关的几个内核参数,这些都能通过pro ... -
linux内核定时器的实现
2009-10-31 01:44 10124由于linux还不是一个实时的操作系统,因此如果需要更高精度, ... -
linux内核中tcp连接的断开处理
2009-10-25 21:47 10213我们这次主要来分析相关的两个断开函数close和shotdow ... -
linux内核tcp的定时器管理(二)
2009-10-05 20:52 5334这次我们来看后面的3个定时器; 首先是keep alive定 ... -
linux内核tcp的定时器管理(一)
2009-10-04 23:29 9766在内核中tcp协议栈有6种 ... -
linux 内核tcp接收数据的实现
2009-09-26 20:24 14389相比于发送数据,接收数据更复杂一些。接收数据这里和3层的接口是 ... -
linux 内核tcp数据发送的实现
2009-09-10 01:41 19661在分析之前先来看下SO_RCVTIMEO和SO_SNDTIME ... -
tcp connection setup的实现(三)
2009-09-03 00:34 5131先来看下accept的实现. 其实accept的作用很简单, ... -
tcp connection setup的实现(二)
2009-09-01 00:46 8379首先来看下内核如何处理3次握手的半连接队列和accept队列( ... -
tcp connection setup的实现(一)
2009-08-23 04:10 5746bind的实现: 先来介绍几个地址结构. struct ... -
linux内核中socket的实现
2009-08-15 04:38 21003首先来看整个与socket相关的操作提供了一个统一的接口sys ...
相关推荐
Linux TCP IP 协议栈分析Linux TCP IP 协议栈分析Linux TCP IP 协议栈分析
文中给出了在Linux下EtherNet/IP协议的实现方法。本程序也可方便的移植到嵌入式系统中,作为EtherNet/IP网络上的一个智能节点。
基于Linux2.6 TCP/IP协议栈源代码分析。
Linux 中TCPIP协议实现及嵌入式应用 北京航空航天大学出版社
深入浅出Linux TCP IP协议栈.pdf
Linux 中TCP IP协议实现及嵌入式应用,北京航空航天大学出版社
linux TCP IP协议栈源码解析资料大全
Linux TCP IP 协议栈分析 Linux2.6 协议栈源代码分析
Linux TCP_IP协议栈的设计及实现特点.pdf
基于 linux 2.6.18 内核源码,对ip协议栈分析。 下载后,评个分。谢谢哈。
深入浅出linux tcp_ip协议栈 清晰版 共4部分,要下就全部下,不然浪费分
tcp/ip在linux下得实现tcp/ip在linux下得实现tcp/ip在linux下得实现tcp/ip在linux下得实现tcp/ip在linux下得实现tcp/ip在linux下得实现tcp/ip在linux下得实现tcp/ip在linux下得实现
linux c TC P IP 协议实现QQ公聊 私聊 传文件等功能 本人的毕业设计 可以移植到开发板上 实现开发板中的通信。 还有文档说明。
IP电话的TCP/IP协议的实现方法.docxIP电话的TCP/IP协议的实现方法.docxIP电话的TCP/IP协议的实现方法.docxIP电话的TCP/IP协议的实现方法.docxIP电话的TCP/IP协议的实现方法.docxIP电话的TCP/IP协议的实现方法....
第7章讲解了网络层IP协议的实现。第8~9章介绍传输层数据收发过程,重点介绍基于套接字的TCP/UDP传输实现。第10章讨论了Linux内核套接字层的实现,以及套接字层与应用层、传输层之间的接口。第11章介绍网络应用软件...
深入浅出linux tcp_ip协议栈2 清晰版 共4部分要下就全部下。不然浪费分
linux TCP/ip协议栈源码分析文档,逐块分析协议栈各个子模块。
深入浅出Linux+TCP_IP协议栈 共三卷 part1