网络子系统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 ...
随机推荐
- C语言 · 矩阵相乘 · 算法提高
算法提高 矩阵相乘 时间限制:1.0s 内存限制:256.0MB 问题描述 小明最近在为线性代数而头疼,线性代数确实很抽象(也很无聊),可惜他的老师正在讲这矩阵乘法这一段内容. 当然 ...
- sublime text2 配置
2.使用Package Control组件安装 也可以安装package control组件,然后直接在线安装: 按Ctrl+`调出console 粘贴以下代码到底部命令行并回车:import url ...
- 奇妙的go语言(面向对象)
[ 声明:版权全部.欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 有过C++语言学习经历的朋友都知道.面向对象主要包含了三个基本特征:封装.继承和多态.封装,就 ...
- 关于c# 发射的调用并进行缓存
private static object CreateObject(string AssemblyPath, string classNamespace) { object objObject = ...
- MVC教程三:URL匹配
1.使用{parameter}做模糊匹配 {parameter}:花括弧加任意长度的字符串,字符串不能定义成controller和action字母.默认的就是模糊匹配. 例如:{admin}. usi ...
- 如果你不知道这11款常见的Web应用程序框架 就说明你out了
本文推荐了11款常见的Web应用程序框架,并列出了相关的学习资料和下载文档.如果对这些项目还不熟悉,就赶紧学起来吧~ Rails Rails是Ruby on Rails的简称,是一款开源的Web应用框 ...
- free 和delete 把指针怎么啦?
别看 free 和 delete 的名字恶狠狠的(尤其是 delete),它们只是把指针所指的内存给 释放掉,但并没有把指针本身干掉. 发现指针 p 被 free 以后其地址仍然不变(非 NULL), ...
- (转)_declspec(dllexport)
先看代码:以下是在dev-c++里建立自已的dll时的dll.h里面的代码,这里面有一个:_declspec(dllexport) #ifndef _DLL_H_#define _DLL_H_//防重 ...
- php -- realpath($path) 函数
PHP realpath路径函数会检测$path指向的目标文件(或文件夹)是否真实存在,相当于调用了file_exists($path). 1.如果目标文件存在且不是符号连接(linux下俗称“软链接 ...
- css -- css选择器
选择器 例子 例子描述 CSS .class .intro 选择 class="intro" 的所有元素. 1 #id #firstname 选择 id="firstna ...