tcp/ip源代码(17)——ip_fragment
- /*
- * This IP datagram is too large to be sent in one piece. Break it up into
- * smaller pieces (each of size equal to IP header plus
- * a block of the data of the original IP data part) that will yet fit in a
- * single device frame, and queue such a frame for sending.
- */
- 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);
- 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 -EMSGSIZE;
- }
- /*
- * Setup starting values.
- */
- hlen = iph->ihl * 4;
- /* 这里的mtu为真正的MTU-IP报文头,即允许的最大IP数据长度 */
- mtu = dst_mtu(&rt->dst) - hlen; /* Size of data space */
- #ifdef CONFIG_BRIDGE_NETFILTER
- if (skb->nf_bridge)
- mtu -= nf_bridge_mtu_reduction(skb);
- #endif
- /* 为这个skb_buff置上分片完成的标志 */
- IPCB(skb)->flags |= IPSKB_FRAG_COMPLETE;
- /* When frag_list is given, use it. First, check its validity:
- * some transformers could create wrong frag_list or break existing
- * one, it is not prohibited. In this case fall back to copying.
- *
- * LATER: this step can be merged to real generation of fragments,
- * we can switch to copy when see the first bad fragment.
- */
- /* 根据前面的学习,我们知道4层有可能会将数据包分片。这些分片存放在skb的frag_list中*/
- if (skb_has_frags(skb)) {
- /* skb_buffer已经有了一个frag list */
- struct sk_buff *frag, *frag2;
- /* 拿到数据包的长度 */
- int first_len = skb_pagelen(skb);
- if (first_len - hlen > mtu ||
- ((first_len - hlen) & 7) ||
- (iph->frag_off & htons(IP_MF|IP_OFFSET)) ||
- skb_cloned(skb))
- goto slow_path; //跳到slow_path
- skb_walk_frags(skb, frag) {
- /* 检查每个分片,如果有一个分片不符合要求,就只能使用slow path */
- /* Correct geometry. */
- if (frag->len > mtu ||
- ((frag->len & 7) && frag->next) ||
- skb_headroom(frag) hlen)
- goto slow_path_clean;
- /* Partially cloned skb? */
- if (skb_shared(frag))
- goto slow_path_clean;
- BUG_ON(frag->sk);
- if (skb->sk) {
- frag->sk = skb->sk;
- frag->destructor = sock_wfree;
- }
- skb->truesize -= frag->truesize;
- }
- /* Everything is OK. Generate! */
- /* 现在可以进行fast path了*/
- err = 0;
- offset = 0;
- /* 拿到frag list */
- frag = skb_shinfo(skb)->frag_list;
- /* 重置原来的frag list,相当于从skb_buff上取走了frag list */
- skb_frag_list_init(skb);
- /*
- 得到实际的数据长度,置分片标志位和校验和
- */
- skb->data_len = first_len - skb_headlen(skb);
- skb->len = first_len;
- iph->tot_len = htons(first_len);
- iph->frag_off = htons(IP_MF);
- ip_send_check(iph);
- for (;;) {
- /* Prepare header of the next frame,
- * before previous one went down. */
- if (frag) {
- /* 表示checksm已经算好*/
- frag->ip_summed = CHECKSUM_NONE;
- /* 设置传输层*/
- skb_reset_transport_header(frag);
- __skb_push(frag, hlen);
- /* 设置网络层 */
- skb_reset_network_header(frag);
- memcpy(skb_network_header(frag), iph, hlen);
- iph = ip_hdr(frag);
- iph->tot_len = htons(frag->len);
- ip_copy_metadata(frag, skb);
- if (offset == 0)
- ip_options_fragment(frag);
- offset = skb->len - hlen;
- iph->frag_off = htons(offset>>3);
- if (frag->next != NULL)
- iph->frag_off |= htons(IP_MF);
- /* Ready, complete checksum */
- /* 计算分片的校验和 */
- ip_send_check(iph);
- }
- err = output(skb);
- if (!err)
- IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGCREATES);
- if (err || !frag)
- break;
- skb = frag;
- frag = skb->next;
- skb->next = NULL;
- }
- if (err == 0) {
- IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGOKS);
- return 0;
- }
- while (frag) {
- skb = frag->next;
- kfree_skb(frag);
- frag = skb;
- }
- IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
- return err;
- slow_path_clean:
- /* 清除shared sk_buff */
- skb_walk_frags(skb, frag2) {
- if (frag2 == frag)
- break;
- frag2->sk = NULL;
- frag2->destructor = NULL;
- skb->truesize = frag2->truesize;
- }
- }
- slow_path:
- left = skb->len - hlen; /* Space per frame */
- ptr = hlen; /* Where to start from */
- /* for bridged IP traffic encapsulated inside f.e. a vlan header,
- * we need to make room for the encapsulating header
- */
- ll_rs = LL_RESERVED_SPACE_EXTRA(rt->dst.dev, nf_bridge_pad(skb));
- /*
- * Fragment the datagram.
- */
- offset = (ntohs(iph->frag_off) & IP_OFFSET) 3;
- /* 通过IP_MF标志位,判断是否是最后一个分片 */
- not_last_frag = iph->frag_off & htons(IP_MF);
- /*
- * Keep copying data until we run out.
- */
- while (left > 0) {
- /* 计算分片长度 */
- len = left;
- /* IF: it doesn't fit, use 'mtu' - the data space left */
- if (len > mtu)
- len = mtu;
- /* IF: we are not sending upto and including the packet end
- then align the next start on an eight byte boundary */
- if (len left) {
- len &= ~7;
- }
- /*
- * Allocate buffer.
- */
- if ((skb2 = alloc_skb(len hlen ll_rs, GFP_ATOMIC)) == NULL) {
- NETDEBUG(KERN_INFO "IP: frag: no memory for new fragment!\n");
- err = -ENOMEM;
- goto fail;
- }
- /*
- * Set up data on packet
- */
- ip_copy_metadata(skb2, skb);
- skb_reserve(skb2, ll_rs);
- skb_put(skb2, len hlen);
- skb_reset_network_header(skb2);
- skb2->transport_header = skb2->network_header hlen;
- /*
- * Charge the memory for the fragment to any owner
- * it might possess
- */
- if (skb->sk)
- skb_set_owner_w(skb2, skb->sk);
- /*
- * Copy the packet header into the new buffer.
- */
- skb_copy_from_linear_data(skb, skb_network_header(skb2), hlen);
- /*
- * Copy a block of the IP datagram.
- */
- if (skb_copy_bits(skb, ptr, skb_transport_header(skb2), len))
- BUG();
- left -= len;
- /*
- * Fill in the new header fields.
- */
- /* 填充网络层 */
- iph = ip_hdr(skb2);
- iph->frag_off = htons((offset >> 3));
- /* ANK: dirty, but effective trick. Upgrade options only if
- * the segment to be fragmented was THE FIRST (otherwise,
- * options are already fixed) and make it ONCE
- * on the initial skb, so that all the following fragments
- * will inherit fixed options.
- */
- /* 如果是第一个分片, 填充ip option */
- if (offset == 0)
- ip_options_fragment(skb);
- /*
- * Added AC : If we are fragmenting a fragment that's not the
- * last fragment then keep MF on each bit
- */
- /* 设置IP_MF标志位 */
- if (left > 0 || not_last_frag)
- iph->frag_off |= htons(IP_MF);
- ptr = len;
- offset = len;
- /*
- * Put this fragment into the sending queue.
- */
- iph->tot_len = htons(len hlen);
- ip_send_check(iph);
- err = output(skb2);
- if (err)
- goto fail;
- IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGCREATES);
- }
- kfree_skb(skb);
- IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGOKS);
- return err;
- fail:
- kfree_skb(skb);
- IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
- return err;
- }
tcp/ip源代码(17)——ip_fragment相关推荐
- TCP/IP协议端口大全
TCP/IP协议端口大全 应用层网关服务 Internet 连接共享 (ICS)/Internet 连接防火墙 (ICF) 服务的这个子组件对允许网络协议通过防火墙并在 Internet 连接 ...
- tcp/ip 协议栈Linux源码分析四 IPv4分片 ip_fragment函数分析
内核版本:3.4.39 很多项目涉及到IP分片的时候都是绕过去了,感觉分片挺难的.但是老这么做也不行啊,抽空分析了内核的分片处理函数ip_fragment,也不是特别复杂,感觉挺简单的,看来事情只有实 ...
- -1-7 java 网络编程基本知识点 计算机网络 TCP/IP协议栈 通信必备 tcp udp
计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来, 在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统. 网络编程 ...
- linux下IPROTO_TCP,TCP/IP协议栈在Linux内核中的运行时序分析
可选题目三:TCP/IP协议栈在Linux内核中的运行时序分析 在深入理解Linux内核任务调度(中断处理.softirg.tasklet.wq.内核线程等)机制的基础上,分析梳理send和recv过 ...
- TCP/IP详解--第十八章
第18章 TCP连接的建立与终止 18.1 引言 TCP是一个面向连接的协议.无论哪一方向另一方发送数据之前,都必须先在双方之间 建立一条连接.本章将详细讨论一个TCP连接是如何建立的以及 ...
- TCP/IP详解--第八章
第8章 Traceroute程序 8.1 引言 由Van Jacobson编写的 Traceroute程序是一个能更深入探索TCP/IP协议的方便可用的工具. 尽管不能保证从源端发往目的端的两 ...
- TCP/IP详解--第一章
说明:专栏中的内容是<TCP/IP详解>这本书,博主分享在此. 第1章概 述 1.1 引言 很多不同的厂家生产各种型号的计算机,它们运行完全不同的操作系统,但 TCP/IP协 ...
- 《TCP/IP详解 卷1:协议》第4章 ARP:地址解析协议
4.1 引言 本章我们要讨论的问题是只对TCP/IP协议簇有意义的IP地址.数据链路如以太网或令牌环网都有自己的寻址机制(常常为48 bit地址),这是使用数据链路的任何网络层都必须遵从的.一个网络如 ...
- C#使用TCP/IP与ModBus进行通讯
C#使用TCP/IP与ModBus进行通讯 1. ModBus的 Client/Server模型 2. 数据包格式及MBAP header (MODBUS Application Protocol h ...
- 在Debian 4.0rc3上编译内核2.6.24时加入Layer7模块笔记[防火墙中在TCP/IP第七层Layer7应用层阻挡QQ,MSN等软件的应用]...
作者:何祖彬[RobinHe] Mail:zubin.he@gmail.com 始于2008年8月3日 上午 版本号:KernelLayer7-V1.0-20080803,2008年8月3日首版 转载 ...
最新文章
- 因女朋友的一个建议,这位程序员创立仅 551 天公司就被 10 亿美元收购了
- 计算机系统结构教程卷子,计算机系统结构试卷试题.docx
- 【数据结构与算法】二项队列的Java实现
- Ruffer Investment共持有略高于3%的比特币敞口
- [转]VUE优秀UI组件库合集
- jq获取页面url后边带的参数
- openopc.opcerror: dispatch: 无效的类字符串_实战PyQt5: 064-MV框架中的Model类
- vos系统是什么?vos网络电话系统怎样搭建?
- ftp上传文件到服务器上,ftp上传文件到服务器上
- 服务器被攻击的常见手段以及解决方法
- EfficientNET_V1
- iOS 开发:『Runtime』详解(二)Method Swizzling
- 给自己一个拼搏的理由
- randon变换(拉东变换)
- 开通阿里云的对象存储服务OSS
- Python 文件 tell() 方法
- 调研分析:全球与中国多媒体投影仪镜头市场现状及未来发展趋势
- [ARM嵌入式系统开发]第一章之嵌入式系统的软硬件
- 求数列极差(贪心算法)
- linux 规避锐捷认证(版本三)