//调用路径ip_rcv->ip_rcv_finish->dst_input->(skb->dst->input)
//ip_forward以回调函数的形式,保存在skb->dst->input,input在通过ip_route_input路由封包时被设置
//函数的主要任务:
// 1.更新ttl
// 2.如果路由被重定向,则向发送方发送icmp重定向报文
// 2.如果有选项,通过ip_forward_options处理在转发时需要更新的选项
// 3.通过ip_output,将报文传递到ip发送路径上
//skb的下一跳信息,在ip_rcv->ip_rcv_finish中,已经通过ip_route_input设置,保存在skb->dst中
1.1 int ip_forward(struct sk_buff *skb)
{
struct iphdr *iph;
struct rtable *rt;
struct ip_options * opt = &(IPCB(skb)->opt);//ip协议控制块,由ip_options_compile初始化 //XFRM是 Linux 2.6 内核为安全处理引入的一个可扩展功能框架
if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb))
goto drop;
//
if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))//对router alert选项的处理
return NET_RX_SUCCESS; if (skb->pkt_type != PACKET_HOST)//重复检查,l2地址非本机,直接丢弃
goto drop; skb->ip_summed = CHECKSUM_NONE;//需要软件重新计算校验和 iph = skb->nh.iph; if (iph->ttl <= 1)//数据帧到期
goto too_many_hops;
//XFRM路由
if (!xfrm4_route_forward(skb))
goto drop; iph = skb->nh.iph;
rt = (struct rtable*)skb->dst;
//处理严源路由选项
//rt->rt_dst 目的ip地址
//rt->rt_gateway 当目的主机直连时,rt_gateway匹配目的地址,当需要通过网关到达目的地址时,rt_gateway设置为下一条网关
//skb->dst在ip_options_rcv_srr中,使用选项中指定的ip地址作为目标地址,通过路由查找,设置为第一个非本机ip的单播路由项
if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)//由于是严源路由选项,因此下一跳地址,必须等于源路由选项中列出的地址
goto sr_failed; if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+rt->u.dst.header_len))//检查skb是否被共享,如果被共享的话,拷贝一份,并在头部预留l3+l2
goto drop;
iph = skb->nh.iph;
//递减跳数
ip_decrease_ttl(iph);
//RTCF_DOREDIRECT在ip_route_input_slow中被设置,表示ICMP_REDIRECT必须被送回源地址
if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr)
ip_rt_send_redirect(skb); skb->priority = rt_tos2priority(iph->tos);//通过tos字段计算skb在规则队列中的优先级 return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, rt->u.dst.dev,
ip_forward_finish); sr_failed: icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0);
goto drop; too_many_hops:
icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
drop:
kfree_skb(skb);
return NET_RX_DROP;
}
//调用路径ip_forward->netfilter hooks->ip_forward_finish
1.2 static inline int ip_forward_finish(struct sk_buff *skb)
{
struct ip_options * opt = &(IPCB(skb)->opt); IP_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS); if (unlikely(opt->optlen))
ip_forward_options(skb);//处理宽松路由选项和time stamp选项 return dst_output(skb);//调用ip_output
}
//处理在转发时需要更新的选项
// 1.record route选项
// 2.源路由选项
// 3.time stamp选项
1.3 void ip_forward_options(struct sk_buff *skb)
{
struct ip_options * opt = &(IPCB(skb)->opt);
unsigned char * optptr;
struct rtable *rt = (struct rtable*)skb->dst;
unsigned char *raw = skb->nh.raw;
//record route选项
if (opt->rr_needaddr) {//说明为出口skb,因为入口skb在ip_options_compile已经被使用首选源地址填写
optptr = (unsigned char *)raw + opt->rr;
ip_rt_get_source(&optptr[optptr[2]-5], rt);
opt->is_changed = 1;
}
if (opt->srr_is_hit) {//表示在源路由选项列表中,有可用的下一跳ip地址
int srrptr, srrspace; optptr = raw + opt->srr; for ( srrptr=optptr[2], srrspace = optptr[1];
srrptr <= srrspace;
srrptr += 4
) {
if (srrptr + 3 > srrspace)
break;
if (memcmp(&rt->rt_dst, &optptr[srrptr-1], 4) == 0)//下一跳地址在源路由地址列表中
break;
}
if (srrptr + 3 <= srrspace) {//表示下一跳在源路由地址列表中
opt->is_changed = 1;
ip_rt_get_source(&optptr[srrptr-1], rt);
skb->nh.iph->daddr = rt->rt_dst;//更新目的地址为下一跳的地址
optptr[2] = srrptr+4;//更新选项的ptr[2]指针到下一跳
} else if (net_ratelimit())
printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n");
if (opt->ts_needaddr) {
optptr = raw + opt->ts;
ip_rt_get_source(&optptr[optptr[2]-9], rt);
opt->is_changed = 1;
}
}
if (opt->is_changed) {
opt->is_changed = 0;
ip_send_check(skb->nh.iph);//计算ip校验和
}
}

网络子系统46_ip协议数据帧的转发的更多相关文章

  1. 网络子系统48_ip协议数据帧的发送

    //ip协议与l4协议接口,l4通过此接口向下l3传递数据帧 //函数主要任务: // 1.通过路由子系统路由封包 // 2.填充l3报头 // 3.ip分片 // 4.计算校验和 // 5.衔接邻居 ...

  2. 网络的分层协议总结(转发:https://www.cnblogs.com/Zhang-wj/p/5907534.html)

    网络的分层协议总结 OSI七层模型OSI 中的层            功能                                                        TCP/IP ...

  3. 网络子系统42_ip协议处理函数_数据帧的接收

    //向协议栈注册l3处理函数 1.1 void dev_add_pack(struct packet_type *pt) { int hash; //ptype_all ptype_base共用一把锁 ...

  4. 网络子系统54_ip协议分片重组_定位ipq

    //为分片确定正确的ipq结构 // 定位5元组 // 1.<id, 源ip, 目的ip, l4协议> 可通过ip报文获取 // 2.user 通过ip_defrag给出,指出重组是由谁发 ...

  5. 网络子系统55_ip协议分片重组_加入ipq

    //ip分片加入到正确的ipq结构 //调用路径:ip_defrag->ip_frag_queue // 处理过程: // 1.正在被释放的ipq,不处理新加入的分片(ipq正在被释放由last ...

  6. 网络子系统45_ip协议tos处理

    //ip报头tos字段,一个字节 // 二进制位:[0 1 2] [3] [4] [5] [6] [7] // 1.[0 1 2] 表示优先级: // 000 路由 // 001 优先级 // 010 ...

  7. 网络子系统53_ip协议分片重组_内存阈值

    //调用路径:ip_defrag->ip_evictor // 分片重组时,可使用内存上下限: // 1.sysctl_ipfrag_high_thresh 可用内存上限 // 2.sysctl ...

  8. Linux 网络子系统之网络协议接口层(一)

    Linux 网络设备驱动之网络协议接口层介绍. 网络协议接口层最主要的功能是给上层协议提供透明的数据包发送和接收接口. 当上层ARP或IP需要发送数据包时,它将调用网络协议接口层的dev_queue_ ...

  9. Linux内核笔记--网络子系统初探

    内核版本:linux-2.6.11 本文对Linux网络子系统的收发包的流程进行一个大致梳理,以流水账的形式记录从应用层write一个socket开始到这些数据被应用层read出来的这个过程中linu ...

随机推荐

  1. uWSGI的stats注释,送给需要的人,欢迎指正

    吐槽先,对于uWSGI状态信息没有文档说明这样一个现实,我只想说一句:F*CK YOU!!! 花了2天时间,累得眼珠子疼,针对这鬼畜的stats,借助Total Commander和VS大概撸了一边u ...

  2. exit和wait一起可以彻底清除子进程的资源

    #include<stdio.h> #include<unistd.h> #include<sys/types.h> #include<stdlib.h> ...

  3. JavaScrip——初学(三个常用对话框及方法调用)

    一. 三个常用对话框: 1.都必须写在<scrip></scrip> <body> <font>alert("报错")</fo ...

  4. ATM交换机 和普通交换机区别

    运行在 ATM协议上的交换机 普通的是运行在 以太网协议上的 ATM交换机 转发的是广域网二层协议数据包,以太网交换机转发的是局域网二层协议数据包. 网络的ATM是指:异步传输模式,全称是什么 Asy ...

  5. Maven_POM配置详解

    本文转载,方便以后查阅,转载地址:http://blog.csdn.net/ithomer/article/details/9332071 <project xmlns="http:/ ...

  6. Ajax-java中的ajax使用,以及编码问题

    结合Ajax类使用:http://www.cnblogs.com/hfultrastrong/p/7267171.html javascript代码: <script type="te ...

  7. 解决spring-boot-starter-logging与log4j冲突

    由于公司在super-bom里配置了检查规则,build项目时遇到错误: [ERROR] [XXX Enforcer Rules] find DuplicateClasses Found in:org ...

  8. 二叉树的java实现

    一.分析 一个二叉树节点有三个部分,一个是指向左子树的部分,一个是指向右子树的部分,另外一个是数据部分.可以把这个节点抽象成一个节点对象,给对象有两个节点对象属性和一个数据属性.如下图: 一个二叉树有 ...

  9. 从实例中学习grid布局

    对于Web开发者来说,网页布局一直是个比较重要的问题. Web 布局主要经历了以下四个阶段: 1.table表格布局: 2.float浮动及position定位布局: 3.flex弹性盒模型布局,革命 ...

  10. 很有必要了解的HTML嵌套规则

    最近在重新学习HTML的知识,算是对HTML的一个重新认识吧!别小看了这东西,一切的网页可都是以它为基础的!下面就详细归纳一下HTML标签的嵌套规则吧,希望对大家有所帮助. XHTML的标签有许多:d ...