温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

TCP/IP协议如何实现ip分片

发布时间:2021-09-19 18:22:38 阅读:734 作者:小新 栏目:大数据
开发者测试专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

小编给大家分享一下TCP/IP协议如何实现ip分片,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

分析一下ip分片。首先我们要先了解为什么需要分片。比如在以太网中,使用CSMA/CD协议(由网卡实现),他规定了一个链路层数据包(不包括mac头,但是这一版内核实现的时候是包括了mac头的大小)的最大值(MTU)和最小值。所以如果上层的包大于这个阈值就需要被分片。而分片和组包的实现是在ip层。我们看一下具体的逻辑。ip分片的逻辑在ip_fragment函数里实现。

void ip_fragment(    struct sock *sk,     struct sk_buff *skb,     struct device *dev,     int is_frag)

定义的一些变量。

    struct iphdr *iph;    unsigned char *raw;    unsigned char *ptr;    struct sk_buff *skb2;    int left, mtu, hlen, len;    int offset;    unsigned long flags;    // mac首地址    raw = skb->data;    // ip头首地址,hard_header_len为mac头大小    iph = (struct iphdr *) (raw + dev->hard_header_len);    skb->ip_hdr = iph;    // ip头的大小,不包括数据部分    hlen = (iph->ihl * sizeof(unsigned long));    // ip包总大小减去ip层等于ip报文的数据长度,即需要分片的部分的大小    left = ntohs(iph->tot_len) - hlen;      // ip头+mac头    hlen += dev->hard_header_len;       // 每个分片的数据部分长度等于mac层的mtu减去mac头和ip头,即mac层的mtu包括了mac头、ip头、ip数据部分的总和。    mtu = (dev->mtu - hlen);            // 数据部分首地址    ptr = (raw + hlen);     

判断是否可以分片。

    // 设置了不能分片则发送icmp报文,可以对照ip报文格式看    if (ntohs(iph->frag_off) & IP_DF)    {        icmp_send(skb,ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, dev->mtu, dev);        return;    }

判断即将被分片的ip包是否本身也是一个分片。即经过了多次ip分片。

/*    该ip报文本身就是一个分片,现在需要进行再次分片,    偏移的首地址是该报文的首地址乘以8,因为再次被分片的报文,他的偏移是    基于原来未被分片的数据的偏移。而不是针对当前这个分片的偏移*/    if (is_frag & 2)        offset = (ntohs(iph->frag_off) & 0x1fff<< 3;    else        offset = 0

开始处理分片。

    // 还有则继续处理    while(left > 0)    {           // ip包默认承载的字节数,但是如果大于mtu的话则取小的值,即mtu        len = left;        // 大于mtu则还要分片,即只能承载mtu大小的字节,否则就是最后一个分片        if (len > mtu)            len = mtu;        /*            剩下的字节比mtu大的时候下面的判断会成立,            即剩下的字节还不能在这次发送完,还要继续分片            除8乘8即取8的倍数大小,不一定等于mtu         */        if (len < left)        {            len/=8;            len*=8;        }        // len 为这一分片承载的数据大小        // 申请新的skb,大小为mac头+ip头+数据部分长度        if ((skb2 = alloc_skb(len + hlen,GFP_ATOMIC)) == NULL)        {            return;        }        skb2->arp = skb->arp;        skb2->free = 1;        // 总大小是mac头+ip头+数据部分长度        skb2->len = len + hlen;        // 指向刚分配的内存首地址,开始复制数据        skb2->h.raw=(char *) skb2->data;        save_flags(flags);        restore_flags(flags);        // ip地址        skb2->raddr = skb->raddr;           // raw指向mac头首地址,这里把mac报头和ip报头+选项都复制到skb中,ip选项应该只复制到第一个分片,这里会复制到每一个分片中        memcpy(skb2->h.raw, raw, hlen);        // 复制数据部分,长度为len,ptr指向原ip报文中数据部分的首地址,        memcpy(skb2->h.raw + hlen, ptr, len);        // 剩下需要分片的字节数        left -= len;        // 指向ip头首地址        skb2->h.raw+=dev->hard_header_len;        iph = (struct iphdr *)(skb2->h.raw);        // 设置该分片的偏移,除以8,见ip协议的规定        iph->frag_off = htons((offset >> 3));        /*            1. 还有数据,则置MF,还要更多分片            2. is_frag =1;说明该分片后面还有更多分片。            表示被分片的数据本身就是一个ip分片,即再分片。            所以该报文下的所有分片MF都是1。        */        if (left > 0 || (is_frag & 1))            iph->frag_off |= htons(IP_MF);        // 更新数据指针和偏移        ptr += len;        offset += len;        // 发送分片        ip_queue_xmit(sk, dev, skb2, 2);    }
分片主要的逻辑是

1 申请一个新的内存,把待分片报文中的mac头、ip头,复制到新内存,然后数据部分切一块继续复制到内存后面。如此,直到分片完毕
2 修改ip报文中的一些字段的值 ,比如MF。
3 调底层接口逐个发送分片
分片的逻辑不算复杂,不讲解的太详细了。

以上是“TCP/IP协议如何实现ip分片”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:https://my.oschina.net/u/4217331/blog/4379091

AI

开发者交流群×