Linux内核分析 - 网络[八补]:IP协议补充
副标题[/!--empirenews.page--] 内核版本:2.6.34 在前一篇”IP协议”中对报文接收时IP层的处理进行了分析,本篇分析将针对报文发送时IP层的处理。 传输层处理完后,会调用ip_push_pending_frames()将报文传递给IP层: ip_push_pending_frames() -> ip_local_out() -> __ip_local_out() 在ip_push_pending_frames()中,会设置第一个IP分片的报头字段,tot_len和 check不会设置。 int ip_local_out(struct sk_buff *skb) { int err; err = __ip_local_out(skb); if (likely(err == 1)) err = dst_output(skb); return err; } __ip_local_out():设置IP报头字节总长度tot_len,校验和check。 iph->tot_len = htons(skb- >len); ip_send_check(iph); 最后调用dst_output()发送数据给IP层,dst_output()实际调用skb_dst(skb)->output(skb) ,skb_dst(skb)就是skb所对应的路由项。skb_dst(skb)指向的是路由项dst_entry,它的input在收到报文时赋值 ip_local_deliver(),而output在发送报文时赋值ip_output()。 return nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev, dst_output); 在IP层的调用过程如下: ip_output() -> ip_finish_output() - > ip_finish_output2() -> hh->hh_output() 在ip_output()中,设置了dev与协议号,从IP层往下,就是以dev驱 动数据传输了。 skb->dev = dev; skb->protocol = htons(ETH_P_IP); 在ip_finish_output()中,判断如果报文过大,则先调用ip_fragment()进行 分片(后面会对这个函数进行分析),然后调用ip_finish_output2()发送。 if (skb->len > ip_skb_dst_mtu (skb) && !skb_is_gso(skb)) return ip_fragment(skb, ip_finish_output2); else return ip_finish_output2(skb); 情况一:ip_fragment() ip_fragment()与ip_append_data()是IP层传送报文很重要的 两个函数,弄清它们之间的关系很重要。 ip_append_data()是上层构造向IP层传送数据的skb使用的,它会根据MTU值对传送 数据进行分片,后续分片链在第一个分片的frag_list上;如果设备支持SG,那么同一个分片内容(当分片内容是多次输入得到的 )不一定在一个线性空间上,后续输入的分片内容存在分片的frags数组中。只有第一个分片才有frag_list,而每个分片都能拥 有frags。由ip_append_data()构造好的skb大致如下图所示: ip_fragments()字面 意思是分片,但实际上分片工作已经由ip_append_data()完成了,它只在上层分片出现问题时重新进行分片。它的主要作用还是 完成分片的后续工作。假设一个报文被分成了三份skb1, skb2, skb3,它们将独立的传递到网络上,但显然ip_append_data()得 到的skb还不是独立的,skb1包含了整个报文的信息,分片报文也链在frag_list上;而skb2, skb3则缺少IP报头的信息,如分片 的偏移,分片的标识,校验和等。ip_fragments()做的主要工作就是将skb拆分成能独立发送的报文。由ip_fragments()处理后 的skb如图所示: (编辑:云计算网_泰州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |