tcp-fs.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.  * tcp-fs: TCP with "fast start", a procedure for avoiding the penalty of
  4.  * slow start when a connection resumes after a pause. The connection tries
  5.  * to reuse values old values of variables such as cwnd_, ssthresh_, srtt_,
  6.  * etc., with suitable modifications. The same procedure as used in tcp-asym
  7.  * is used to clock out packets until ack clocking kicks in. A connection 
  8.  * doing fast start protects itself and other connections in the network against 
  9.  * the adverse consequences of stale information by (a) marking all packets sent 
  10.  * during fast start as low priority for the purposes of a priority-drop router, 
  11.  * and (b) quickly detecting the loss of several fast start packets and falling 
  12.  * back to a regular slow start, almost as if a fast start had never been attempted
  13.  * in the first place.
  14.  * 
  15.  * Contributed by Venkat Padmanabhan (padmanab@cs.berkeley.edu), 
  16.  * Daedalus Research Group, U.C.Berkeley
  17.  */
  18. #include "tcp-fs.h"
  19. void ResetTimer::expire(Event *) {
  20. a_->timeout(TCP_TIMER_RESET);
  21. }
  22. static class TcpFsClass : public TclClass {
  23. public:
  24. TcpFsClass() : TclClass("Agent/TCP/FS") {}
  25. TclObject* create(int, const char*const*) {
  26. return (new TcpFsAgent());
  27. }
  28. } class_tcpfs;
  29. static class RenoTcpFsClass : public TclClass {
  30. public:
  31. RenoTcpFsClass() : TclClass("Agent/TCP/Reno/FS") {}
  32. TclObject* create(int, const char*const*) {
  33. return (new RenoTcpFsAgent());
  34. }
  35. } class_renotcpfs;
  36. static class NewRenoTcpFsClass : public TclClass {
  37. public:
  38. NewRenoTcpFsClass() : TclClass("Agent/TCP/Newreno/FS") {}
  39. TclObject* create(int, const char*const*) {
  40. return (new NewRenoTcpFsAgent());
  41. }
  42. } class_newrenotcpfs;
  43. #ifdef USE_FACK
  44. static class FackTcpFsClass : public TclClass {
  45. public:
  46. FackTcpFsClass() : TclClass("Agent/TCP/Fack/FS") {}
  47. TclObject* create(int, const char*const*) {
  48. return (new FackTcpFsAgent());
  49. }
  50. } class_facktcpfs;
  51. #endif
  52. /* mark packets sent as part of fast start */
  53. void
  54. TcpFsAgent::output_helper(Packet *pkt)
  55. {
  56. hdr_tcp *tcph = hdr_tcp::access(pkt);
  57. double now = Scheduler::instance().clock();
  58. double idle_time = now - last_recv_time_;
  59. double timeout = ((t_srtt_ >> 3) + t_rttvar_) * tcp_tick_ ;
  60. maxseq_ = max(maxseq_, highest_ack_);
  61. /* 
  62.  * if the connection has been idle (with no outstanding data) for long 
  63.  * enough, we enter the fast start phase. We compute the start and end
  64.  * sequence numbers that define the fast start phase. Note that the
  65.  * first packet to be sent next is not included because it would have
  66.  * been sent even with regular slow start.
  67.  */
  68. if ((idle_time > timeout) && (maxseq_ == highest_ack_) && (cwnd_ > 1)){
  69. /*
  70.  * We set cwnd_ to a "safe" value: cwnd_/2 if the connection
  71.  * was in slow start before the start of the idle period and
  72.  * cwnd_-1 if it was in congestion avoidance phase.
  73.  */
  74. /* if (cwnd_ < ssthresh_+1)*/
  75. if (cwnd_ < ssthresh_)
  76. cwnd_ = int(cwnd_/2);
  77. else
  78. cwnd_ -= 1;
  79. /* set the start and end seq. nos. for the fast start phase */
  80. fs_startseq_ = highest_ack_+2;
  81. fs_endseq_ = highest_ack_+window()+1;
  82. fs_mode_ = 1;
  83. }
  84. /* initially set fs_ flag to 0 */
  85. hdr_flags::access(pkt)->fs_ = 0;
  86. /* check if packet belongs to the fast start phase. */
  87. if (tcph->seqno() >= fs_startseq_ && tcph->seqno() < fs_endseq_ && fs_mode_) {
  88. /* if not a retransmission, mark the packet */
  89. if (tcph->seqno() > maxseq_) {
  90. hdr_flags::access(pkt)->fs_ = 1;
  91. }
  92. }
  93. }
  94. /* update last_output_time_ */
  95. void
  96. TcpFsAgent::recv_helper(Packet *) 
  97. {
  98. double now = Scheduler::instance().clock();
  99. last_recv_time_ = now;
  100. }
  101. /* schedule the next burst of data (of size at most maxburst) */
  102. void 
  103. TcpFsAgent::send_helper(int maxburst) 
  104. {
  105. /* 
  106.  * If there is still data to be sent and there is space in the
  107.  * window, set a timer to schedule the next burst. Note that
  108.  * we wouldn't get here if TCP_TIMER_BURSTSEND were pending,
  109.  * so we do not need an explicit check here.
  110.  */
  111. if (t_seqno_ <= highest_ack_ + window() && t_seqno_ < curseq_) {
  112. burstsnd_timer_.resched(t_exact_srtt_*maxburst/window());
  113. }
  114. }
  115. #ifdef USE_FACK
  116. /* schedule the next burst of data (of size at most maxburst) */
  117. void 
  118. FackTcpFsAgent::send_helper(int maxburst) 
  119. {
  120. /* 
  121.  * If there is still data to be sent and there is space in the
  122.  * window, set a timer to schedule the next burst. Note that
  123.  * we wouldn't get here if TCP_TIMER_BURSTSEND were pending,
  124.  * so we do not need an explicit check here.
  125.  */
  126. if ((t_seqno_ <= fack_ + window() - retran_data_) && (!timeout_) && (t_seqno_ < curseq_)) {
  127. burstsnd_timer_.resched(t_exact_srtt_*maxburst/window());
  128. }
  129. }
  130. #endif
  131. /* do appropriate processing depending on the length of idle time */
  132. void
  133. TcpFsAgent::send_idle_helper() 
  134. {
  135. // Commented out because they are not used
  136. // XXX What processing belong here??? - haoboy
  137. //double now = Scheduler::instance().clock();
  138. //double idle_time = now - last_recv_time_;
  139. }
  140. /* update srtt estimate */
  141. void
  142. TcpFsAgent::recv_newack_helper(Packet *pkt) 
  143. {
  144. hdr_tcp *tcph = hdr_tcp::access(pkt);
  145. double tao = Scheduler::instance().clock() - tcph->ts_echo();
  146. double g = 1/8; /* gain used for smoothing rtt */
  147. double h = 1/4; /* gain used for smoothing rttvar */
  148. double delta;
  149. int ackcount, i;
  150. /*
  151.  * If we are counting the actual amount of data acked, ackcount >= 1.
  152.  * Otherwise, ackcount=1 just as in standard TCP.
  153.  */
  154. if (count_bytes_acked_)
  155. ackcount = tcph->seqno() - last_ack_;
  156. else
  157. ackcount = 1;
  158. newack(pkt);
  159. maxseq_ = max(maxseq_, highest_ack_);
  160. if (t_exact_srtt_ != 0) {
  161. delta = tao - t_exact_srtt_;
  162. if (delta < 0)
  163. delta = -delta;
  164. /* update the fine-grained estimate of the smoothed RTT */
  165. if (t_exact_srtt_ != 0) 
  166. t_exact_srtt_ = g*tao + (1-g)*t_exact_srtt_;
  167. else
  168. t_exact_srtt_ = tao;
  169. /* update the fine-grained estimate of mean deviation in RTT */
  170. delta -= t_exact_rttvar_;
  171. t_exact_rttvar_ += h*delta;
  172. }
  173. else {
  174. t_exact_srtt_ = tao;
  175. t_exact_rttvar_ = tao/2;
  176. }
  177. /* grow cwnd. ackcount > 1 indicates that actual ack counting is enabled */
  178. for (i=0; i<ackcount; i++)
  179. opencwnd();
  180. /* check if we are out of fast start mode */
  181. if (fs_mode_ && (highest_ack_ >= fs_endseq_-1)) 
  182. fs_mode_ = 0;
  183. /* if the connection is done, call finish() */
  184. if ((highest_ack_ >= curseq_-1) && !closed_) {
  185. closed_ = 1;
  186. finish();
  187. }
  188. }
  189. void
  190. NewRenoTcpFsAgent::partialnewack_helper(Packet* pkt)
  191. {
  192. partialnewack(pkt);
  193. /* Do this because we may have retracted maxseq_ */
  194. maxseq_ = max(maxseq_, highest_ack_);
  195. if (fs_mode_ && fast_loss_recov_) {
  196. /* 
  197.  * A partial new ack implies that more than one packet has been lost
  198.  * in the window. Rather than recover one loss per RTT, we get out of
  199.  * fast start mode and do a slow start (no rtx timeout, though).
  200.  */
  201. timeout_nonrtx(TCP_TIMER_RESET);
  202. }
  203. else {
  204. output(last_ack_ + 1, 0);
  205. }
  206. }
  207. void 
  208. TcpFsAgent::set_rtx_timer()
  209. {
  210. if (rtx_timer_.status() == TIMER_PENDING)
  211. rtx_timer_.cancel();
  212. if (reset_timer_.status() == TIMER_PENDING)
  213. reset_timer_.cancel();
  214. if (fs_mode_ && fast_loss_recov_ && fast_reset_timer_)
  215. reset_timer_.resched(rtt_exact_timeout());
  216. else if (fs_mode_ && fast_loss_recov_)
  217. reset_timer_.resched(rtt_timeout());
  218. else 
  219. rtx_timer_.resched(rtt_timeout());
  220. }
  221. void 
  222. TcpFsAgent::cancel_rtx_timer() 
  223. {
  224. rtx_timer_.force_cancel();
  225. reset_timer_.force_cancel();
  226. }
  227. void 
  228. TcpFsAgent::cancel_timers() 
  229. {
  230. rtx_timer_.force_cancel();
  231. reset_timer_.force_cancel();
  232. burstsnd_timer_.force_cancel();
  233. delsnd_timer_.force_cancel();
  234. }
  235. void 
  236. TcpFsAgent::timeout_nonrtx(int tno) 
  237. {
  238. if (tno == TCP_TIMER_RESET) {
  239. fs_mode_ = 0; /* out of fast start mode */
  240. dupacks_ = 0; /* just to be safe */
  241. if (highest_ack_ == maxseq_ && !slow_start_restart_) {
  242. /*
  243.  * TCP option:
  244.  * If no outstanding data, then don't do anything.
  245.  */
  246. return;
  247. };
  248. /* 
  249.  * If the pkt sent just before the fast start phase has not
  250.  * gotten through, treat this as a regular rtx timeout.
  251.  */
  252. if (highest_ack_ < fs_startseq_-1) {
  253. maxseq_ = fs_startseq_ - 1;
  254. recover_ = maxseq_;
  255. timeout(TCP_TIMER_RTX);
  256. }
  257. /* otherwise decrease window size to 1 but don't back off rtx timer */
  258. else {
  259. if (highest_ack_ > last_ack_)
  260. last_ack_ = highest_ack_;
  261. maxseq_ = last_ack_;
  262. recover_ = maxseq_;
  263. last_cwnd_action_ = CWND_ACTION_TIMEOUT;
  264. slowdown(CLOSE_CWND_INIT);
  265. timeout_nonrtx_helper(tno);
  266. }
  267. }
  268. else {
  269. TcpAgent::timeout_nonrtx(tno);
  270. }
  271. }
  272. void 
  273. TcpFsAgent::timeout_nonrtx_helper(int tno)
  274. {
  275. if (tno == TCP_TIMER_RESET) {
  276. reset_rtx_timer(0,0);
  277. send_much(0, TCP_REASON_TIMEOUT, maxburst_);
  278. }
  279. }
  280. void 
  281. RenoTcpFsAgent::timeout_nonrtx_helper(int tno)
  282. {
  283. if (tno == TCP_TIMER_RESET) {
  284. dupwnd_ = 0;
  285. dupacks_ = 0;
  286. TcpFsAgent::timeout_nonrtx_helper(tno);
  287. }
  288. }
  289. void 
  290. NewRenoTcpFsAgent::timeout_nonrtx_helper(int tno)
  291. {
  292. if (tno == TCP_TIMER_RESET) {
  293. dupwnd_ = 0;
  294. dupacks_ = 0;
  295. TcpFsAgent::timeout_nonrtx_helper(tno);
  296. }
  297. }
  298. #ifdef USE_FACK
  299. void 
  300. FackTcpFsAgent::timeout_nonrtx_helper(int tno)
  301. {
  302. if (tno == TCP_TIMER_RESET) {
  303. timeout_ = FALSE;
  304. retran_data_ = 0;
  305. fack_ = last_ack_;
  306. t_seqno_ = last_ack_ + 1;
  307. reset_rtx_timer(TCP_REASON_TIMEOUT, 0);
  308. send_much(0, TCP_REASON_TIMEOUT);
  309. }
  310. }
  311. #endif