tcp-newreno.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:9k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 1990, 1997 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted
  7.  * provided that the above copyright notice and this paragraph are
  8.  * duplicated in all such forms and that any documentation,
  9.  * advertising materials, and other materials related to such
  10.  * distribution and use acknowledge that the software was developed
  11.  * by the University of California, Lawrence Berkeley Laboratory,
  12.  * Berkeley, CA.  The name of the University may not be used to
  13.  * endorse or promote products derived from this software without
  14.  * specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19. #ifndef lint
  20. static const char rcsid[] =
  21.     "@(#) $Header: /cvsroot/nsnam/ns-2/tcp/tcp-newreno.cc,v 1.57 2006/06/14 18:05:30 sallyfloyd Exp $ (LBL)";
  22. #endif
  23. //
  24. // newreno-tcp: a revised reno TCP source, without sack
  25. //
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <sys/types.h>
  29. #include "packet.h"
  30. #include "ip.h"
  31. #include "tcp.h"
  32. #include "flags.h"
  33. static class NewRenoTcpClass : public TclClass {
  34. public:
  35. NewRenoTcpClass() : TclClass("Agent/TCP/Newreno") {}
  36. TclObject* create(int, const char*const*) {
  37. return (new NewRenoTcpAgent());
  38. }
  39. } class_newreno;
  40. NewRenoTcpAgent::NewRenoTcpAgent() : newreno_changes_(0), 
  41.   newreno_changes1_(0), acked_(0), firstpartial_(0), 
  42.   partial_window_deflation_(0), exit_recovery_fix_(0)
  43. {
  44. bind("newreno_changes_", &newreno_changes_);
  45. bind("newreno_changes1_", &newreno_changes1_);
  46. bind("exit_recovery_fix_", &exit_recovery_fix_);
  47. bind("partial_window_deflation_", &partial_window_deflation_);
  48. }
  49. /* 
  50.  * Process a packet that acks previously unacknowleges data, but
  51.  * does not take us out of Fast Retransmit.
  52.  */
  53. void NewRenoTcpAgent::partialnewack(Packet* pkt)
  54. {
  55. hdr_tcp *tcph = hdr_tcp::access(pkt);
  56. if (partial_window_deflation_) {
  57. // Do partial window deflation before resetting last_ack_
  58. unsigned int deflate = 0; // Should initialize it?? - haoboy
  59. if (tcph->seqno() > last_ack_) // assertion
  60. deflate = tcph->seqno() - last_ack_;
  61. else 
  62.    printf("False call to partialnewack:  deflate %u 
  63. last_ack_ %dn", deflate, last_ack_);
  64. if (dupwnd_ > deflate)
  65. dupwnd_ -= (deflate - 1);
  66. else {
  67. cwnd_ -= (deflate - dupwnd_);
  68. // Leave dupwnd_ > 0 to flag "fast recovery" phase
  69. dupwnd_ = 1; 
  70. }
  71. if (cwnd_ < 1) {cwnd_ = 1;}
  72. }
  73. last_ack_ = tcph->seqno();
  74. highest_ack_ = last_ack_;
  75. if (t_seqno_ < last_ack_ + 1)
  76. t_seqno_ = last_ack_ + 1;
  77. if (rtt_active_ && tcph->seqno() >= rtt_seq_) {
  78. rtt_active_ = 0;
  79. t_backoff_ = 1;
  80. }
  81. }
  82. void NewRenoTcpAgent::partialnewack_helper(Packet* pkt)
  83. {
  84. if (!newreno_changes1_ || firstpartial_ == 0) {
  85. firstpartial_ = 1;
  86. /* For newreno_changes1_, 
  87.  * only reset the retransmit timer for the first
  88.  * partial ACK, so that, in the worst case, we
  89.  * don't have to wait for one packet retransmitted
  90.  * per RTT.
  91.  */
  92. newtimer(pkt);
  93. }
  94. partialnewack(pkt);
  95. output(last_ack_ + 1, 0);
  96. }
  97. int
  98. NewRenoTcpAgent::allow_fast_retransmit(int /* last_cwnd_action_*/)
  99. {
  100. return 0;
  101. }
  102. void
  103. NewRenoTcpAgent::dupack_action()
  104. {
  105.         int recovered = (highest_ack_ > recover_);
  106. int recovered1 = (highest_ack_ == recover_);
  107.         int allowFastRetransmit = allow_fast_retransmit(last_cwnd_action_);
  108.         if (recovered || (!bug_fix_ && !ecn_) || allowFastRetransmit 
  109.            || (bugfix_ss_ && highest_ack_ == 0)) {
  110.                 // (highest_ack_ == 0) added to allow Fast Retransmit
  111.                 //  when the first data packet is dropped.
  112.                 //  Bug report from Mark Allman.
  113.                 goto reno_action;
  114.         }
  115. if (bug_fix_ && less_careful_ && recovered1) {
  116. /*
  117.  * For the Less Careful variant, allow a Fast Retransmit
  118.  *  if highest_ack_ == recover.
  119.  * RFC 2582 recommends the Careful variant, not the 
  120.  *  Less Careful one.
  121.  */
  122.                 goto reno_action;
  123. }
  124.         if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
  125.                 last_cwnd_action_ = CWND_ACTION_DUPACK;
  126.                 /*
  127.                  * What if there is a DUPACK action followed closely by ECN
  128.                  * followed closely by a DUPACK action?
  129.                  * The optimal thing to do would be to remember all
  130.                  * congestion actions from the most recent window
  131.                  * of data.  Otherwise "bugfix" might not prevent
  132.                  * all unnecessary Fast Retransmits.
  133.                  */
  134.                 reset_rtx_timer(1,0);
  135.                 output(last_ack_ + 1, TCP_REASON_DUPACK);
  136. dupwnd_ = numdupacks_;
  137.                 return;
  138.         }
  139.         if (bug_fix_) {
  140. if (bugfix_ts_ && tss[highest_ack_ % tss_size_] == ts_echo_)
  141. goto reno_action;
  142. else if (bugfix_ack_ && cwnd_ > 1 && highest_ack_ - prev_highest_ack_ <= numdupacks_)
  143. goto reno_action;
  144. else
  145.                 /*
  146.                  * The line below, for "bug_fix_" true, avoids
  147.                  * problems with multiple fast retransmits in one
  148.                  * window of data.
  149.                  */
  150.                  return;
  151.         }
  152. reno_action:
  153.         recover_ = maxseq_;
  154.         reset_rtx_timer(1,0);
  155.         if (!lossQuickStart()) {
  156.                 trace_event("NEWRENO_FAST_RETX");
  157.          last_cwnd_action_ = CWND_ACTION_DUPACK;
  158.          slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
  159.          output(last_ack_ + 1, TCP_REASON_DUPACK);       // from top
  160. dupwnd_ = numdupacks_;
  161. }
  162.         return;
  163. }
  164. void NewRenoTcpAgent::recv(Packet *pkt, Handler*)
  165. {
  166. hdr_tcp *tcph = hdr_tcp::access(pkt);
  167. int valid_ack = 0;
  168. /* Use first packet to calculate the RTT  --contributed by Allman */
  169.         if (qs_approved_ == 1 && tcph->seqno() > last_ack_)
  170. endQuickStart();
  171.         if (qs_requested_ == 1)
  172.                 processQuickStart(pkt);
  173. if (++acked_ == 1) 
  174. basertt_ = Scheduler::instance().clock() - firstsent_;
  175. /* Estimate ssthresh based on the calculated RTT and the estimated
  176.    bandwidth (using ACKs 2 and 3).  */
  177. else if (acked_ == 2)
  178. ack2_ = Scheduler::instance().clock();
  179. else if (acked_ == 3) {
  180. ack3_ = Scheduler::instance().clock();
  181. new_ssthresh_ = int((basertt_ * (size_ / (ack3_ - ack2_))) / size_);
  182. if (newreno_changes_ > 0 && new_ssthresh_ < ssthresh_)
  183. ssthresh_ = new_ssthresh_;
  184. }
  185. #ifdef notdef
  186. if (pkt->type_ != PT_ACK) {
  187. fprintf(stderr,
  188. "ns: confiuration error: tcp received non-ackn");
  189. exit(1);
  190. }
  191. #endif
  192.         /* W.N.: check if this is from a previous incarnation */
  193.         if (tcph->ts() < lastreset_) {
  194.                 // Remove packet and do nothing
  195.                 Packet::free(pkt);
  196.                 return;
  197.         }
  198. ++nackpack_;
  199. ts_peer_ = tcph->ts();
  200. if (hdr_flags::access(pkt)->ecnecho() && ecn_)
  201. ecn(tcph->seqno());
  202. recv_helper(pkt);
  203. recv_frto_helper(pkt);
  204. if (tcph->seqno() > last_ack_) {
  205. if (tcph->seqno() >= recover_ 
  206.     || (last_cwnd_action_ != CWND_ACTION_DUPACK)) {
  207. if (dupwnd_ > 0) {
  208.      dupwnd_ = 0;
  209.      if (last_cwnd_action_ == CWND_ACTION_DUPACK)
  210. last_cwnd_action_ = CWND_ACTION_EXITED;
  211.      if (exit_recovery_fix_) {
  212. int outstanding = maxseq_ - tcph->seqno() + 1;
  213. if (ssthresh_ < outstanding)
  214.                                         cwnd_ = ssthresh_;
  215.                                 else
  216.                                         cwnd_ = outstanding;
  217.     }
  218. }
  219. firstpartial_ = 0;
  220. recv_newack_helper(pkt);
  221. if (last_ack_ == 0 && delay_growth_) {
  222. cwnd_ = initial_window();
  223. }
  224. } else {
  225. /* received new ack for a packet sent during Fast
  226.  *  Recovery, but sender stays in Fast Recovery */
  227. if (partial_window_deflation_ == 0)
  228. dupwnd_ = 0;
  229. partialnewack_helper(pkt);
  230. }
  231. } else if (tcph->seqno() == last_ack_) {
  232. if (hdr_flags::access(pkt)->eln_ && eln_) {
  233. tcp_eln(pkt);
  234. return;
  235. }
  236. if (++dupacks_ == numdupacks_) {
  237. dupack_action();
  238.                         if (!exitFastRetrans_)
  239.                                 dupwnd_ = numdupacks_;
  240. } else if (dupacks_ > numdupacks_ && (!exitFastRetrans_
  241.       || last_cwnd_action_ == CWND_ACTION_DUPACK)) {
  242. trace_event("NEWRENO_FAST_RECOVERY");
  243. ++dupwnd_; // fast recovery
  244. /* For every two duplicate ACKs we receive (in the
  245.  * "fast retransmit phase"), send one entirely new
  246.  * data packet "to keep the flywheel going".  --Allman
  247.  */
  248. if (newreno_changes_ > 0 && (dupacks_ % 2) == 1)
  249. output (t_seqno_++,0);
  250. } else if (dupacks_ < numdupacks_ && singledup_ ) {
  251.                         send_one();
  252.                 }
  253. }
  254.         if (tcph->seqno() >= last_ack_)
  255.                 // Check if ACK is valid.  Suggestion by Mark Allman.
  256.                 valid_ack = 1;
  257. Packet::free(pkt);
  258. #ifdef notyet
  259. if (trace_)
  260. plot();
  261. #endif
  262. /*
  263.  * Try to send more data
  264.  */
  265.         if (valid_ack || aggressive_maxburst_)
  266. if (dupacks_ == 0) 
  267. /*
  268.  * Maxburst is really only needed for the first
  269.  *  window of data on exiting Fast Recovery.
  270.  */
  271. send_much(0, 0, maxburst_);
  272. else if (dupacks_ > numdupacks_ - 1 && newreno_changes_ == 0)
  273. send_much(0, 0, 2);
  274. }