加入收藏 | 设为首页 | 会员中心 | 我要投稿 应用网_丽江站长网 (http://www.0888zz.com/)- 科技、建站、数据工具、云上网络、机器学习!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux内核分析 - 网络[八补]:IP协议补充

发布时间:2016-05-28 22:18:07 所属栏目:Linux 来源:网络整理
导读:内核版本:2.6.34 在前一篇IP协议中对报文接收时IP层的处理进行了分析,本篇分析将针对报文发送时IP层的处理。 传输层处理完后,会调用ip_push_pending_frames(

调用相应发送函数发送给下一层。有关hh和neighbour 参考”ARP模块”。

if (dst->hh)     
 return neigh_hh_output(dst->hh, skb);     
else if (dst->neighbour)     
 return dst->neighbour->output(skb);

在创建邻居表项时neighbour->output()被赋值,比如收到arp报文 ,在arp_process() -> neigh_event_ns()中创建报文相应的邻居表项,而neigh->ops和neigh->output根据情况赋予 不同的值。

if (dev->header_ops->cache)     
 neigh->ops = &arp_hh_ops;     
else 
 neigh->ops = &arp_generic_ops;     
if (neigh->nud_state&NUD_VALID)     
 neigh->output = neigh->ops->connected_output;     
else 
 neigh->output = neigh->ops->output;

邻居表项创建后,相应的hh缓存项并没有创建,当向邻居表项中的 主机发送报文时,先调用neigh->output(),假设neigh->ops被赋值arp_generiv_ops,则neigh->output= neigh_resolve_output,而在neigh_resolve_output()函数中,会创建hh缓存项,其中hh->output= dev_queue_xmit()。

所以,无论哪种情况,hh->output还是neigh->output,最终都是调用dev_queue_xmit()向下层传送报文的。这也是IP层 下传送报文的统一方式-dev_queue_xmit()。虽然调用接口相同,但IP层下的各个协议模块都是有设备的概念的,因此每个模块 的设备都不相同,在每个模块中都会更换skb->dev为下层的设备,而dev_queue_xmit()最终使用的是skb->dev特定的函数 进行发送的,这样实现了各模块的接口一致。

dev_queue_xmit() 发送函数

skb_needs_linearize()判断是否要对报文 进行线性处理,如果需要,它返回1,由__skb_linearize()完成线性处理。线性处理就是将报文的所有内容放到线性地址空间, 不能有分片的存在。在发送报文时,ip_append_data()对过长的报文进行了分片frag_list,多次添加时使用了SG特性frags(如 果支持)。skb_needs_linearize()就是判断设备能否处理ip_append_data()所做的分片工作。判断条件很简单:skb有分片即 frag_list,但设备不支持分片NETIF_F_FRAGLIST;skb应用了SG但设备不支持NETIF_F_SG或者是有一个分片在highmem中。最后 的线性化函数__skb_linearize()也很简单,它调用__pskb_pull_tail(skb, skb->data_len),data_len就是非线性空间的长 度,__pskb_pull_taill会将这部分数据拷贝到skb->data,从而完成线性化。明显看到,不支持分片的设备在做线性化处理 时会多一次数据拷贝操作。

if (skb_needs_linearize(skb, dev) && __skb_linearize(skb))     
 goto out_kfree_skb;

ip_summed==CHECKSUM_PARTIAL表示协议栈并没有计算完校验和,只计算了IP头,伪头等,将传 输层的数据部分留给了硬件进行计算。dev_can_checksum()判断设备是否能计算校验和,如果不能的话,则skb_checksum_help ()软件的计算校验和。

if (skb->ip_summed == CHECKSUM_PARTIAL) {     
 skb_set_transport_header(skb, skb->csum_start - skb_headroom(skb));     
 if (!dev_can_checksum(dev, skb) && skb_checksum_help(skb))     
  goto out_kfree_skb;     
}

(编辑:应用网_丽江站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读