网络子系统46_ip协议数据帧的转发
//调用路径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协议数据帧的转发的更多相关文章
- 网络子系统48_ip协议数据帧的发送
//ip协议与l4协议接口,l4通过此接口向下l3传递数据帧 //函数主要任务: // 1.通过路由子系统路由封包 // 2.填充l3报头 // 3.ip分片 // 4.计算校验和 // 5.衔接邻居 ...
- 网络的分层协议总结(转发:https://www.cnblogs.com/Zhang-wj/p/5907534.html)
网络的分层协议总结 OSI七层模型OSI 中的层 功能 TCP/IP ...
- 网络子系统42_ip协议处理函数_数据帧的接收
//向协议栈注册l3处理函数 1.1 void dev_add_pack(struct packet_type *pt) { int hash; //ptype_all ptype_base共用一把锁 ...
- 网络子系统54_ip协议分片重组_定位ipq
//为分片确定正确的ipq结构 // 定位5元组 // 1.<id, 源ip, 目的ip, l4协议> 可通过ip报文获取 // 2.user 通过ip_defrag给出,指出重组是由谁发 ...
- 网络子系统55_ip协议分片重组_加入ipq
//ip分片加入到正确的ipq结构 //调用路径:ip_defrag->ip_frag_queue // 处理过程: // 1.正在被释放的ipq,不处理新加入的分片(ipq正在被释放由last ...
- 网络子系统45_ip协议tos处理
//ip报头tos字段,一个字节 // 二进制位:[0 1 2] [3] [4] [5] [6] [7] // 1.[0 1 2] 表示优先级: // 000 路由 // 001 优先级 // 010 ...
- 网络子系统53_ip协议分片重组_内存阈值
//调用路径:ip_defrag->ip_evictor // 分片重组时,可使用内存上下限: // 1.sysctl_ipfrag_high_thresh 可用内存上限 // 2.sysctl ...
- Linux 网络子系统之网络协议接口层(一)
Linux 网络设备驱动之网络协议接口层介绍. 网络协议接口层最主要的功能是给上层协议提供透明的数据包发送和接收接口. 当上层ARP或IP需要发送数据包时,它将调用网络协议接口层的dev_queue_ ...
- Linux内核笔记--网络子系统初探
内核版本:linux-2.6.11 本文对Linux网络子系统的收发包的流程进行一个大致梳理,以流水账的形式记录从应用层write一个socket开始到这些数据被应用层read出来的这个过程中linu ...
随机推荐
- 常用shell命令实战
#!/bin/sh ################### #### 环境变量 ### ################### #主程序目录 #APP_HOME=/apps/svr/apache-to ...
- WPF教程二:布局之StackPanel面板
应用程序界面设计中,合理的元素布局至关重要,它可以方便用户使用,并将信息清晰合理地展现给用户.WPF提供了一套功能强大的工具-面板(Panel),来控制用户界面的布局.你可以使用这些面板控件来排布元素 ...
- Linux下如何查看tomcat是否启动/系统日志等
Linux下如何查看tomcat是否启动/系统日志等 查看tomcat是否启动 ps -ef | grep tomcat 或者 ps -ef | grep java 启动tomcat(在tomca ...
- PHP wamp server问题
只能说各种不顺,天热人烦! 问题一.wampapache服务不能启动之VCRUNTIME140.DLL文件丢失. 这个是缺少VC运行库,查找并安装相应的文件即可. 问题二.wampapche服务不能启 ...
- QT把widget转换成图片后打印
from PyQt5.QtWidgets import (QApplication, QWidget, QTableWidget,QPushButton, QVBoxLayout, QTableWid ...
- UART通信协议
第一部分: UART使用的是 异步,串行通信. 串行通信是指利用一条传输线将资料一位位地顺序传送.特点是通信线路简单,利用简单的线缆就可实现通信,降低成本,适用于远距离通信,但传输速度慢的应用场 ...
- CentOS查看本机公网IP命令
icanhazip.com 使你在任何地方知道你的公网IP地址 icanhazip.com是一个网址,你在浏览器中输入这个网址,你就能得到你的公网IP地址了. 我在Linux下一般使用curl ica ...
- 二分求幂,快速求解a的b次幂
一个引子 如何求得a的b次幂呢,那还不简单,一个for循环就可以实现! void main(void) { int a, b; ; cin >> a >> b; ; i < ...
- js上传本地图片遇到的问题
1.改变页面文件上传默认的样式 <input type="text" size="20" id="upfile" style=&quo ...
- poj 3740 Easy Finding(Dancing Links)
Easy Finding Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 15668 Accepted: 4163 Des ...