//ip协议与l4协议接口,l4通过此接口向下l3传递数据帧
//函数主要任务:
// 1.通过路由子系统路由封包
// 2.填充l3报头
// 3.ip分片
// 4.计算校验和
// 5.衔接邻居子系统,向下层传送封包。
1.1 int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
{
struct sock *sk = skb->sk;
struct inet_sock *inet = inet_sk(sk);
struct ip_options *opt = inet->opt;//选项与sock相关
struct rtable *rt;
struct iphdr *iph; //检查skb是否已经被路由
rt = (struct rtable *) skb->dst;
if (rt != NULL)
goto packet_routed;
//检测ip的可用性
//dst->obsolete
// 0 默认值,该结构有效可以被使用
// 2 表示该结构将被删除因而不能被使用
// -1 表示该结构被IPsec和IPv6使用但不被IPv4使用
rt = (struct rtable *)__sk_dst_check(sk, 0);
if (rt == NULL) {//没有可用的路由信息,重新路由封包
u32 daddr; daddr = inet->daddr;//sock中指定的目标ip地址
if(opt && opt->srr)//源路由选项
daddr = opt->faddr;//将第一跳地址作为目标地址 {
struct flowi fl = { .oif = sk->sk_bound_dev_if,//出口设备
.nl_u = { .ip4_u =
{ .daddr = daddr,//对目标地址进行路由,为sock中指定的目的地址,或者在源路由选项时,使用的第一跳地址
.saddr = inet->saddr,//源地址
.tos = RT_CONN_FLAGS(sk) } },//sock中指定的tos
.proto = sk->sk_protocol,//l4协议
.uli_u = { .ports =
{ .sport = inet->sport,
.dport = inet->dport } } };//源端口,目的端口 if (ip_route_output_flow(&rt, &fl, sk, 0))//对出口skb进行路由
goto no_route;
}
__sk_dst_set(sk, &rt->u.dst);
tcp_v4_setup_caps(sk, &rt->u.dst);//根据网卡对tso的支持,更新sk的tso
}
skb->dst = dst_clone(&rt->u.dst);//增加dst的引用计数 packet_routed:
if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)//处理严路由选项,下一跳地址必须为网管地址
goto no_route; iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));//移动skb->data向上,准备填写ip报头
*((__u16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));//设置报头长度为20字节,选项的长度,在ip_options_build中增加
iph->tot_len = htons(skb->len);//总长度,skb中所有数据的长度,包括报头,选项,有效载荷
if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)//检查禁止了分片
iph->frag_off = htons(IP_DF);//设置报头指示禁止分片
else
iph->frag_off = 0;//分片中的偏移量
iph->ttl = ip_select_ttl(inet, &rt->u.dst);//生存周期
iph->protocol = sk->sk_protocol;//指示ip上层的l4协议类型
iph->saddr = rt->rt_src;//源地址,目的地址
iph->daddr = rt->rt_dst;
skb->nh.iph = iph; if (opt && opt->optlen) {//sock中设置了选项
iph->ihl += opt->optlen >> 2;
ip_options_build(skb, opt, inet->daddr, rt, 0);//处理选项
} ip_select_ident_more(iph, &rt->u.dst, sk, skb_shinfo(skb)->tso_segs);//为ip选择id ip_send_check(iph);//ip报头校验和 skb->priority = sk->sk_priority;//skb的优先级为sock的优先级,在dev_queue_xmit中用于在规则队列中排队 return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
dst_output);//调用dst->output,由ip_route_output_flow设置 no_route:
IP_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
kfree_skb(skb);
return -EHOSTUNREACH;
} //调用路径ip_queue_xmit->ip_output或ip_forward_finish->ip_output
1.2 int ip_output(struct sk_buff *skb)
{
IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); if (skb->len > dst_pmtu(skb->dst) && !skb_shinfo(skb)->tso_size)
return ip_fragment(skb, ip_finish_output);//ip分片
else
return ip_finish_output(skb);
} //调用路径ip_output->ip_finish_output
1.3 int ip_finish_output(struct sk_buff *skb)
{
struct net_device *dev = skb->dst->dev; skb->dev = dev;//出口设备
skb->protocol = htons(ETH_P_IP);//skb准备向l2层传送,在skb->protocol中告诉l2层,上层l3的协议类型 return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
ip_finish_output2);//skb被路由之后的netfilter拦截点
}
//调用路径ip_output->ip_finish_output->ip_finish_output2
//函数主要任务:
// 1.保证skb头部足够空间容纳l2帧头
// 2.通过l2帧头缓存,拷贝l2帧头,完成向下层的传输
// 3.没有可供使用的l2帧头缓存,则衔接邻居子系统,交由邻居子系统处理skb
1.4 static inline int ip_finish_output2(struct sk_buff *skb)
{
struct dst_entry *dst = skb->dst;
struct hh_cache *hh = dst->hh;
struct net_device *dev = dst->dev;
int hh_len = LL_RESERVED_SPACE(dev); if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {//skb头空间不足l2头,设备驱动提供了在skb中填充l2头的功能
struct sk_buff *skb2; skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));//重新分配skb头来容纳l2头
if (skb2 == NULL) {
kfree_skb(skb);
return -ENOMEM;
}
if (skb->sk)
skb_set_owner_w(skb2, skb->sk);
kfree_skb(skb);
skb = skb2;
} if (hh) {//l2帧头缓存
int hh_alen; read_lock_bh(&hh->hh_lock);
hh_alen = HH_DATA_ALIGN(hh->hh_len);
memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);//拷贝帧头缓存中的l2帧头到skb中
read_unlock_bh(&hh->hh_lock);
skb_push(skb, hh->hh_len);
return hh->hh_output(skb);//通过l2帧头缓存的output函数,完成skb向下的传递
} else if (dst->neighbour)//没有l2帧头缓存,则需要邻居子系统,获取数据帧的l2地址
return dst->neighbour->output(skb); if (net_ratelimit())
printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n");
kfree_skb(skb);
return -EINVAL;
}

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

  1. 网络子系统46_ip协议数据帧的转发

    //调用路径ip_rcv->ip_rcv_finish->dst_input->(skb->dst->input) //ip_forward以回调函数的形式,保存在skb ...

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

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

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

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

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

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

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

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

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

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

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

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

  8. [转]C#网络编程(订立协议和发送文件) - Part.4

    本文转自:http://www.tracefact.net/CSharp-Programming/Network-Programming-Part4.aspx 源码下载:http://www.trac ...

  9. C#网络编程(订立协议和发送文件) - Part.4

    文件传输 前面两篇文章所使用的范例都是传输字符串,有的时候我们可能会想在服务端和客户端之间传递文件.比如,考虑这样一种情况,假如客户端显示了一个菜单,当我们输入S1.S2或S3(S为Send缩写)时, ...

随机推荐

  1. mongodb 2.6.6 在window10下的安装

    首先感谢波仔的知道,其次感叹下WIN10的牛叉,兼容性还不错. 首先,下载mongodb 2.6.6 安装包,可惜,官网太慢,还得注册.不过还好,我是个好人:http://pan.baidu.com/ ...

  2. wcf系列学习5天速成——第三天 事务的使用

    今天是速成的第三天,再分享一下WCF中比较常用的一种技术,也就是”事务“. 在B2B的项目中,一般用户注册后,就有一个属于自己的店铺,此时,我们就要插入两张表, User和Shop表. 当然,要么插入 ...

  3. Mvc里删除Cooki

    /// <summary> /// 删除Cookie /// </summary> /// <param name="skuID">从购物车选择 ...

  4. SQL Server执行计划那些事儿(2)——查找和扫描

    接下来的文章是记录自己曾经的盲点,同时也透漏了自己的发展历程(可能发展也算不上,只能说是瞎混).当然,一些盲点也在工作和探究过程中慢慢有些眉目,现在也愿意发扬博客园的奉献精神,拿出来和大家分享一下. ...

  5. JAVA 可视化分析工具 第12节

    JAVA 可视化分析工具  第12节 经过前几章对堆内存以及垃圾收集机制的学习,相信小伙伴们已经建立了一套比较完整的理论体系!那么这章我们就根据已有的理论知识,通过可视化工具来实践一番. 我们今天要讲 ...

  6. js中跳转

    <li><a href="javascript:recordRescSifting('+subject.subId+');">'+subject.subNa ...

  7. mysql性能监控工具Innotop

    mysql监控管理工具--innotop 1.innotop安装参考官网:http://innotop.googlecode.com/svn/html/installing.html # wget h ...

  8. Mac Please try running this command again as root/Administrator.

    mac 终端安装程序,需要权限,出现以下提示语句: Please try running this command again as root/Administrator. 需要执行以下命令即可: s ...

  9. SQL Server 统计信息对查询的影响

    优化器根据开消确定选择哪个执行计划,开消又与行数统计信息有关,默认情况下统计信息是在优化的过程中自动生成的. 一旦列被标记为需要统计信息,查询优化器就会查找该列以有的统计信息,如果以有一个统计信息,下 ...

  10. SAR图像与光学图像区别

    按传感器采用的成像波段分类,光学图像通常是指可见光和部分红外波段传感器获取的影像数据.而SAR传感器基本属于微波频段,波长通常在厘米级.可见光图像通常会包含多个波段的灰度信息,以便于识别目标和分类提取 ...