1。ip分片的结构体组织形式
先记录以下特殊的字段:
(1)skb_buff的cb字段 char cb[48],是一个自定义字段,在协议各层处理时,可以存储各协议的私有数据,就是随便自己定义,在ip层分片时存储的是struct inet_skb_parm *,该结构体嵌套两个数据:ip选项 struct ip_options opt; 和 标识字段flags。
(2)skb_buff结构体末尾存储的是分片链表,即该结构体的末尾连续的内存,存储了包含分片数据信息的结构体struct skb_shared_info的指针。
分片信息存储区分:
快速分片:此时,分片信息存储在skb_buff字段的skb_shared_info 由skb_buff组成的frag_list链表中,链表上每个skb_buff是一个分片。
慢速分片:此时,分片信息存储在skb_buff字段的data字段和skb_shared_info 的字段skb_frag_struct frags[MAX_SKB_FRAGS]的page字段中,
ip分片分两种情况即快速分片和慢分片:
快速分片是指分片数据已经在L4层分片成功,这些分片使用存储在结构体skb_shared_info中的sk_buff类型的链,变量frag_list中,由于是做好分片,所以在分片函数里只需要为每个分片增加ip头即可,循环对分片进行增加ip头,交由底层协议,最后至网卡驱动函数。
慢速分片是指上层发送的数据完全存储在skb_buff的data成员中,需要分片函数对data进行拆分,组织ip头信息,交由底层协议,最后至网卡驱动函数。
2。ip分片时机
{ ip_pending_frame,ip_queue_xmit } -》dst_output-》{ ip_mc_output,ip_output } -》NF_HOOK_COND(netfilter ) -》ip_finish_output -》ip_fragment -》ip_finish_output2-》邻居子系统的输出函数()-》dev_queue_xmit-》。。。
ip_queue_xmit中会进行路由查找,确定报文的发送网卡接口
3。ip分片函数解释
ip_fragment函数:
int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
{
struct iphdr *iph;
int ptr;
struct net_device *dev;
struct sk_buff *skb2;
unsigned int mtu, hlen, left, len, ll_rs;
int offset;
__be16 not_last_frag;
struct rtable *rt = skb_rtable(skb);
int err = 0;
dev = rt->dst.dev;
/*
* Point into the IP datagram header.
*/
//ip头指针
iph = ip_hdr(skb);
//如果设置了不允许分片标识,则直接返回一个icmp不可达报文
if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) {
IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
htonl(ip_skb_dst_mtu(skb)));
kfree_skb(skb);
return -EMSGSIZ