博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux 内核网络协议栈 ------ tcp重传数据包 tcp_retransmit_skb 函数
阅读量:4055 次
发布时间:2019-05-25

本文共 5180 字,大约阅读时间需要 17 分钟。

/* This retransmits one SKB.  Policy decisions and retransmit queue * state updates are done by the caller.  Returns non-zero if an * error occurred which prevented the send. */int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb){         struct tcp_sock *tp = tcp_sk(sk);         struct inet_connection_sock *icsk = inet_csk(sk);         unsigned int cur_mss = tcp_current_mss(sk, 0);         int err;          /* Inconslusive MTU probe */         if (icsk->icsk_mtup.probe_size) {                 icsk->icsk_mtup.probe_size = 0;         }          /* Do not sent more than we queued. 1/4 is reserved for possible            * copying overhead: fragmentation, tunneling, mangling etc.          */ // 如果消耗很多的内存做其他事,那么就没有多余的来做队列的处理了~         if (atomic_read(&sk->sk_wmem_alloc) >                                     // sk_wmem_alloc:传输队列大小             min(sk->sk_wmem_queued + (sk->sk_wmem_queued >> 2), sk->sk_sndbuf))   // sk_wmem_queud:固定的队列大小                 return -EAGAIN;          if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) {// 若这样,说明是有一部分数据才需要重传,形如:seq---snd_una---end_seq,前面一半已收到ACK                 if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una))  // 若这样,说明全部ACK,无需重传,BUG                         BUG();                 if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq))  // 一些控制信息检查                         return -ENOMEM;         }          /* If receiver has shrunk his window, and skb is out of          * new window, do not retransmit it. The exception is the          * case, when window is shrunk to zero. In this case          * our retransmit serves as a zero window probe.          */         if (!before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp))    // 如果数据在窗口后面,不会发送             && TCP_SKB_CB(skb)->seq != tp->snd_una)                   return -EAGAIN;          if (skb->len > cur_mss) {   // 如果skb长度 > MSS                 if (tcp_fragment(sk, skb, cur_mss, cur_mss))   // 先分片。再传送                         return -ENOMEM; /* We'll try again later. */         }          /* Collapse two adjacent packets if worthwhile and we can. */  // 我*,这么多条件         if (!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) &&              // SYN包             (skb->len < (cur_mss >> 1)) &&                             // 长度
<半个mss (tcp_write_queue_next(sk, skb) !="tcp_send_head(sk))" && 不是结尾 (!tcp_skb_is_last(sk, skb)) 不是最后一个 (skb_shinfo(skb)->
nr_frags == 0 && // 没有分页数据 skb_shinfo(tcp_write_queue_next(sk, skb))->nr_frags == 0) && (tcp_skb_pcount(skb) == 1 && // gso_segs=1 tcp_skb_pcount(tcp_write_queue_next(sk, skb)) == 1) && (sysctl_tcp_retrans_collapse != 0)) tcp_retrans_try_collapse(sk, skb, cur_mss); // 这个函数不是很明白,待看~~~~~~~~~~~~~~~~~~~~~~~~~ if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk)) // 根据目的地址等条件获取路由,如果获取路由失败就不能发送 return -EHOSTUNREACH; /* Routing failure or similar. */ /* Some Solaris stacks overoptimize and ignore the FIN on a * retransmit when old data is attached. So strip it off * since it is cheap to do so and saves bytes on the network. *///Solaris系统的协议栈有时候会忽略重传SKB上带有的FIN标志的payload,将payload全部剥离掉,节省网络流量 if (skb->len > 0 && (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) && tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) { if (!pskb_trim(skb, 0)) { /* Reuse, even though it does some unnecessary work */ tcp_init_nondata_skb(skb, TCP_SKB_CB(skb)->end_seq - 1, TCP_SKB_CB(skb)->flags); skb->ip_summed = CHECKSUM_NONE; } } /* Make a copy, if the first transmission SKB clone we made * is still in somebody's hands, else make a clone. */ TCP_SKB_CB(skb)->when = tcp_time_stamp; err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); // 这个才是正在的传输函数~~~~~~~~~~~~~~~~~~~~后面再说~~~~~~~~~~~~~~~ // 这个函数就是将数据包发送到下面一层,再慢慢传输出去~~~~~~~~~~~~~~ if (err == 0) { // 发送成功,那么就需要更新TCP统计信息 /* Update global TCP statistics. */ TCP_INC_STATS(TCP_MIB_RETRANSSEGS); tp->total_retrans++; // 整体重传数量++ #if FASTRETRANS_DEBUG > 0 if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) { if (net_ratelimit()) printk(KERN_DEBUG "retrans_out leaked.\n"); }#endif if (!tp->retrans_out) tp->lost_retrans_low = tp->snd_nxt; TCP_SKB_CB(skb)->sacked |= TCPCB_RETRANS; tp->retrans_out += tcp_skb_pcount(skb); // 重传出去的数量+=。。。 /* Save stamp of the first retransmit. */ if (!tp->retrans_stamp) tp->retrans_stamp = TCP_SKB_CB(skb)->when; // 第一次重传时间戳 tp->undo_retrans++; /* snd_nxt is stored to detect loss of retransmitted segment, * see tcp_input.c tcp_sacktag_write_queue(). */ TCP_SKB_CB(skb)->ack_seq = tp->snd_nxt; } return err;}

转载地址:http://vaaci.baihongyu.com/

你可能感兴趣的文章
医疗行业运用企业云盘可以带来什么样的提升
查看>>
媒体广告业如何将内容资产进行高效地综合管理与利用
查看>>
能源化工要怎么管控核心数据
查看>>
媒体广告业如何运用云盘提升效率
查看>>
企业如何运用企业云盘进行数字化转型-实现新发展
查看>>
司法如何运用电子智能化加快现代化建设
查看>>
iSecret&nbsp;1.1&nbsp;正在审核中
查看>>
IOS开发的开源库
查看>>
IOS开发的开源库
查看>>
Jenkins - sonarqube 代码审查
查看>>
Jenkins + Docker + SpringCloud 微服务持续集成(一)
查看>>
Jenkins + Docker + SpringCloud 微服务持续集成 - 单机部署(二)
查看>>
Jenkins + Docker + SpringCloud 微服务持续集成 - 高可用集群部署(三)
查看>>
Golang struct 指针引用用法(声明入门篇)
查看>>
Linux 粘滞位 suid sgid
查看>>
C#控件集DotNetBar安装及破解
查看>>
Winform皮肤控件IrisSkin4.dll使用
查看>>
Winform多线程
查看>>
C# 托管与非托管
查看>>
Node.js中的事件驱动编程详解
查看>>