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

通讯编程

开发平台:

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. /*
  20.  * This is TCP SACK with Rate-Halving, contributed code from Matt
  21.  * Mathis, Jeff Semke, Jamshid Mahdavi, and Kevin Lahey, and
  22.  * described at "http://www.psc.edu/networking/rate-halving/". 
  23.  */
  24. #ifndef lint
  25. static const char rcsid[] =
  26.     "@(#) $Header: /cvsroot/nsnam/ns-2/tcp/tcp-sack-rh.cc,v 1.6 2006/02/21 15:20:20 mahrenho Exp $ (PSC-SACKRH)";
  27. #endif
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <sys/types.h>
  31. #include "ip.h"
  32. #include "tcp.h"
  33. #include "flags.h"
  34. #include "scoreboard-rh.h"
  35. #include "random.h"
  36. #define TRUE    1
  37. #define FALSE   0
  38. #define RH_INCR 0
  39. #define RH_EXACT 11
  40. #define RH_EST 12
  41. #define RH_EST_REPAIR 13
  42. #define RHEH_NONE 0
  43. #define RHEH_COUNTING 1
  44. #define RHEH_NEW_HOLE 2
  45. #define RHEH_RETRANS_OCCURRED 3
  46. //#define DEBUGRH 
  47. class SackRHTcpAgent : public TcpAgent {
  48.  public:
  49.         SackRHTcpAgent();
  50. virtual int window();
  51. virtual void recv(Packet *pkt, Handler*);
  52. virtual void timeout(int tno);
  53. void plot();
  54. virtual void send_much(int force, int reason, int maxburst);
  55. virtual void boundparms();
  56. virtual void estadjust();
  57. virtual void rhclear();
  58. virtual void computefack();
  59. virtual void newack(Packet* pkt);
  60.  protected:
  61. int fack_;           /* the FACK state variable  */
  62. int retran_data_;         /* the number of retransmitted packets in the pipe  */
  63. int num_dupacks_;         /* sigh, I think we still want this for the NewReno case */
  64. int rh_state_;            /* The rate halving state we are in  */
  65. double prior_cwnd_;       /* The value of cwnd at the start of RH  */
  66. int prior_max_seq_;       /* The old value of max_seq  */
  67. int rh_id_;               /* A unique ID for the current adjustment interval  */
  68. int rh_max_;              /* The max ID which has been used so far  */
  69. int rh_est_hole_state_;   /* Status of NewReno style holes during estimation */
  70. int num_retrans_;         /* Number of retransmissions during the estimation state */
  71. int rh_retran_flag_;      /* Flag to indicate a retransmission has occured */
  72. int rh_ecn_flag_;         /* Flag to indicate an ECN was seen during this recovery */
  73. ScoreBoardRH scb_;
  74. };
  75. static class SackRHTcpClass : public TclClass {
  76. public:
  77. SackRHTcpClass() : TclClass("Agent/TCP/SackRH") {}
  78. TclObject* create(int, const char*const*) {
  79. return (new SackRHTcpAgent());
  80. }
  81. } class_sack_rh;
  82. int SackRHTcpAgent::window()
  83. {
  84. return(cwnd_ < wnd_ ? (int) cwnd_ : (int) wnd_);
  85. }
  86. SackRHTcpAgent::SackRHTcpAgent() : fack_(-1), 
  87. retran_data_(0), num_dupacks_(0), rh_state_(RH_INCR), rh_id_(0), rh_max_(0),
  88. rh_est_hole_state_(0), rh_retran_flag_(0), rh_ecn_flag_(0), scb_(&numdupacks_)
  89. {
  90. }
  91. void SackRHTcpAgent::recv(Packet *pkt, Handler*)
  92. {
  93. int old_fack, old_retran_data, old_ack, old_numdupacks;
  94. hdr_tcp *tcph = hdr_tcp::access(pkt);
  95. int ecnecho = (hdr_flags::access(pkt)->ecnecho() && last_ack_ != -1);
  96. int sackpresent = (tcph->sa_length() > 0);
  97. ++nackpack_;
  98. #ifdef DEBUGRH
  99. printf ("ENTER: RH=%02d snd.nxt=%3d fack=%3d ack=%3d retran_data=%03d n",
  100. rh_state_, (int)t_seqno_, fack_, last_ack_, retran_data_);
  101. printf ("       prior_max_seq=%3d prior_cwnd=%f rheh=%2d num_dupacks=%2dn",
  102. prior_max_seq_, prior_cwnd_, rh_est_hole_state_, num_dupacks_);
  103. printf ("       cwnd:%f=%d curseq=%dn",
  104. (float)cwnd_, int(cwnd_), (int)curseq_);
  105. #endif
  106. old_ack = last_ack_;
  107. newack(pkt);
  108. if (ecnecho) rh_ecn_flag_=1;   /*  Remember that we saw an ECN  */
  109. /*  Process any SACK blocks:  */
  110. old_fack = fack_;
  111. old_retran_data = retran_data_;
  112. retran_data_ -= scb_.UpdateScoreBoard (last_ack_, tcph, rh_id_);
  113. old_numdupacks = num_dupacks_;
  114.         if (!sackpresent && (old_ack == last_ack_)) {
  115. num_dupacks_++;
  116. if ((rh_est_hole_state_ == RHEH_COUNTING) && 
  117.     (num_dupacks_ == numdupacks_)) {
  118. rh_est_hole_state_ = RHEH_NEW_HOLE;
  119. }
  120. }
  121. computefack();
  122. /*  7.8  Reordering Exit transitions */
  123. if (!rh_retran_flag_ && !rh_ecn_flag_) {
  124. if (((rh_state_ == RH_EXACT) && !sackpresent && !ecnecho) ||
  125.     ((rh_state_ == RH_EST) && (last_ack_ > old_ack))) {
  126. rh_state_ = RH_INCR;
  127. cwnd_ = prior_cwnd_;
  128. rhclear();
  129. computefack();  /* In case we were estimating it before */
  130. }
  131. }
  132. /*  7.10 Completion of RH_EXACT  */
  133. if (rh_state_ == RH_EXACT) {
  134. if ((fack_ >= prior_max_seq_) || scb_.RetranSacked(rh_id_)) {
  135. boundparms();
  136. rh_state_ = RH_INCR;
  137. rhclear();
  138. }
  139. }
  140. /*  7.11 Completion of RH_EST*  */
  141. if ((rh_state_ == RH_EST) || (rh_state_ == RH_EST_REPAIR)) {
  142. if (last_ack_ >= prior_max_seq_) {
  143. retran_data_ = 0;     /*  Just like a partial ACK, this
  144.   means a retransmission has left
  145.   the network.  */
  146. estadjust();
  147. boundparms();
  148. rh_state_ = RH_INCR;
  149. rhclear();
  150. computefack();   /*  This is needed to restore 
  151.      fack now that we are done estimating */
  152. }
  153. }
  154. /*  7.12 NewReno case  */
  155. if ((rh_state_ == RH_EST) && (cwnd_ <= prior_cwnd_/2)) {
  156. rh_state_ = RH_EST_REPAIR;
  157. }
  158. /*  7.9  Processing partial Acks in RH_EST or RH_EST_REPAIR */
  159. if (((rh_state_ == RH_EST) || (rh_state_ == RH_EST_REPAIR))
  160.     && (last_ack_ > old_ack)) {
  161. retran_data_ = 0;
  162. num_dupacks_ -= (last_ack_ - old_ack - 1);
  163. if (num_dupacks_ >= numdupacks_) {
  164. rh_est_hole_state_ = RHEH_NEW_HOLE;
  165. }
  166. else {
  167. /*  We don't have 3 dupacks on this hole, so 
  168.     go back to counting...  */
  169. rh_est_hole_state_ = RHEH_COUNTING;
  170. }
  171. computefack();  /* Recompute the estimate */
  172. }
  173. /*  Now check the entry conditions:  */
  174. /*  7.4  Entering RH_EXACT  */
  175. if ((rh_state_ == RH_INCR) && (ecnecho || scb_.GetNewHoles() != 0)) {
  176. rh_state_ = RH_EXACT;
  177. prior_cwnd_ = cwnd_;
  178. prior_max_seq_ =  t_seqno_;
  179. cong_action_ = TRUE;
  180. rh_id_ = ++rh_max_;
  181. }
  182. /*  7.5  Entering RH_EST  */
  183. if ((rh_state_ == RH_INCR)  && (num_dupacks_ > 0)) {
  184. rh_state_ = RH_EST;
  185. rh_est_hole_state_ = RHEH_COUNTING;
  186. prior_cwnd_ = cwnd_;
  187. prior_max_seq_ =  t_seqno_;
  188. cong_action_ = TRUE;
  189. rh_id_ = ++rh_max_;
  190. }
  191. if ((rh_state_ == RH_EXACT)  && (num_dupacks_ > 0)) {
  192. rh_state_ = RH_EST;
  193. rh_est_hole_state_ = RHEH_COUNTING;
  194. /*  cong_action_ = TRUE;  */   /*  Don't need it, 
  195.                                    since we already
  196.    sent it  */
  197. rh_id_ = ++rh_max_;
  198. }
  199. if ((rh_state_ == RH_EST_REPAIR)  && (ecnecho)) {
  200. rh_state_ = RH_EST;
  201. prior_cwnd_ = cwnd_;
  202. prior_max_seq_ =  t_seqno_;
  203. cong_action_ = TRUE;
  204. rh_id_ = ++rh_max_;
  205. }
  206. /*  Updating the window:  */
  207. switch (rh_state_) {
  208. case RH_INCR:
  209. /*  Case 7.2:  */
  210. if ((t_seqno_ - old_fack + old_retran_data + 1) >= (int)cwnd_) {
  211. opencwnd();
  212. }
  213. break;
  214. case RH_EXACT:
  215. /*  Case 7.6  */
  216. cwnd_ -= ((float)((fack_ - old_fack) + (scb_.GetNewHoles()))) / 2.0;
  217. break;
  218. case RH_EST:
  219. /*  Case 7.7  */
  220. cwnd_ -= 0.5;
  221. break;
  222. case RH_EST_REPAIR:
  223. /*  Do not modify cwnd in this state  */
  224. break;
  225. }
  226. #ifdef DEBUGRH
  227. printf ("EXIT:  RH=%02d snd.nxt=%3d fack=%3d ack=%3d retran_data=%03d n       cwnd:%f=%d curseq=%dn",
  228. rh_state_, (int)t_seqno_, fack_, last_ack_, retran_data_, (float)cwnd_, int(cwnd_),
  229.         (int)curseq_);
  230. #endif
  231. send_much(FALSE, 0, maxburst_);
  232. Packet::free(pkt);
  233. #ifdef notyet
  234. if (trace_)
  235. plot();
  236. #endif
  237. }
  238. void SackRHTcpAgent::rhclear()
  239. {
  240. rh_id_ = prior_max_seq_ = num_dupacks_ = rh_est_hole_state_ = 
  241. rh_ecn_flag_ = num_retrans_ = rh_retran_flag_ = 0;
  242. prior_cwnd_ = 0;
  243. }
  244. /*  Compute FACK:  */
  245. void SackRHTcpAgent::computefack()
  246. {
  247. if ((rh_state_ == RH_INCR) || (rh_state_ == RH_EXACT)) {
  248. fack_ = scb_.GetFack (last_ack_);
  249. }
  250. else {
  251. fack_ = last_ack_ + num_dupacks_ + 1;
  252. }
  253. }
  254. /*  7.14: Bounding Parameters  */
  255. void SackRHTcpAgent::boundparms()
  256. {
  257. if (cwnd_ > prior_cwnd_/2.0) 
  258. cwnd_ = prior_cwnd_/2.0;
  259. ssthresh_ = cwnd_;
  260. if (ssthresh_ < prior_cwnd_/4.0)
  261. ssthresh_ = (int) (prior_cwnd_/4.0);
  262. }
  263. /*  7.13: Corrections to Estimation  */
  264. void SackRHTcpAgent::estadjust()
  265. {
  266. cwnd_ = (prior_cwnd_ - num_retrans_)/2.0;
  267. }
  268. /*  7.15: Retransmission Timeout  */
  269. void SackRHTcpAgent::timeout(int tno)
  270. {
  271. /* retransmit timer */
  272. if (tno == TCP_TIMER_RTX) {
  273. if (highest_ack_ == maxseq_ && !slow_start_restart_)
  274. /*
  275.  * TCP option:
  276.  * If no outstanding data, then don't do anything.
  277.  */
  278. return;
  279. if (highest_ack_ == -1 && wnd_init_option_ == 2)
  280. /* 
  281.  * First packet dropped, so don't use larger
  282.  * initial windows. 
  283.  */
  284. wnd_init_option_ = 1;
  285. #ifdef DEBUGRH
  286. printf ("timeout. last_ack: %d seqno: %dn", 
  287. (int)last_ack_, (int)t_seqno_);
  288. #endif
  289. if (rh_state_ != RH_INCR) {
  290. /*  4.6  We took a timeout in the middle of
  291.     rate-halving.  Pretend like RH
  292.     never started:  */
  293. cwnd_ = prior_cwnd_;
  294. rhclear();
  295. rh_state_ = RH_INCR;
  296. }
  297. ++nrexmit_;
  298. slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
  299. retran_data_ = 0;
  300. scb_.TimeoutScoreBoard(t_seqno_);
  301. computefack();
  302. /*  Pull back the sequence number -- pretend you never
  303.     sent packets beyond FACK  */
  304. if (t_seqno_ > fack_+1) {
  305. t_seqno_ = fack_+1;
  306. }
  307. reset_rtx_timer(1,1);
  308. last_cwnd_action_ = CWND_ACTION_TIMEOUT;
  309. send_much(0, TCP_REASON_TIMEOUT, maxburst_);
  310. else {
  311. timeout_nonrtx(tno);
  312. }
  313. }
  314. void SackRHTcpAgent::send_much(int force, int reason, int maxburst)
  315. {
  316. register int found, npacket = 0;
  317. int xmit_seqno;
  318. found = 1;
  319. if (!force && delsnd_timer_.status() == TIMER_PENDING)
  320. return;
  321. /*
  322.  * as long as the pipe is open and there is app data to send...
  323.  */
  324. /*  7.3: data transmission  */
  325. while (int(cwnd_) >= (t_seqno_ - fack_ + retran_data_)
  326.         && found) {
  327. if (overhead_ == 0 || force) {
  328. found = 0;
  329. xmit_seqno = scb_.GetNextRetran ();
  330. if (xmit_seqno == -1) { 
  331. /*  Check to see if we have identified a new hole... */
  332. if (((rh_state_ == RH_EST) || (rh_state_ == RH_EST_REPAIR)) &&
  333.     (rh_est_hole_state_ == RHEH_NEW_HOLE)) {
  334. xmit_seqno = last_ack_ + 1;
  335. rh_est_hole_state_ = RHEH_RETRANS_OCCURRED;
  336. num_retrans_++;
  337. retran_data_++;
  338. rh_retran_flag_ = 1;
  339. found = 1;
  340. }
  341. else if ((t_seqno_ < curseq_) && 
  342.  (t_seqno_<=last_ack_+int(wnd_))) {
  343. found = 1;
  344. xmit_seqno = t_seqno_++;
  345. }
  346. } else if (xmit_seqno<=last_ack_+int(wnd_)) {
  347. found = 1;
  348. scb_.MarkRetran (xmit_seqno, t_seqno_, rh_id_);
  349. retran_data_++;
  350. rh_retran_flag_ = 1;
  351. }
  352. if (found) {
  353. #ifdef DEBUGRH
  354. printf ("      Sending: %3dn", xmit_seqno);
  355. #endif
  356. output(xmit_seqno, reason);
  357. if (t_seqno_ <= xmit_seqno)
  358. t_seqno_ = xmit_seqno + 1;
  359. npacket++;
  360. }
  361. } else if (!(delsnd_timer_.status() == TIMER_PENDING)) {
  362. /*
  363.  * Set a delayed send timeout.
  364.  * This is only for the simulator,to add some
  365.  *   randomization if speficied.
  366.  */
  367. delsnd_timer_.resched(Random::uniform(overhead_));
  368. return;
  369. }
  370. if (maxburst && npacket == maxburst)
  371. break;
  372. } /* while */
  373. }
  374. void SackRHTcpAgent::plot()
  375. {
  376. #ifdef notyet
  377. double t = Scheduler::instance().clock();
  378. sprintf(trace_->buffer(), "t %g %d rtt %gn", 
  379. t, class_, t_rtt_ * tcp_tick_);
  380. trace_->dump();
  381. sprintf(trace_->buffer(), "t %g %d dev %gn", 
  382. t, class_, t_rttvar_ * tcp_tick_);
  383. trace_->dump();
  384. sprintf(trace_->buffer(), "t %g %d win %fn", t, class_, cwnd_);
  385. trace_->dump();
  386. sprintf(trace_->buffer(), "t %g %d bck %dn", t, class_, t_backoff_);
  387. trace_->dump();
  388. #endif
  389. }
  390. /*
  391.  * Process a packet that acks previously unacknowleged data.
  392.  *
  393.  * The only thing we change here is the policy for clearing
  394.  * RTO backoff...
  395.  *
  396.  */
  397. void SackRHTcpAgent::newack(Packet* pkt)
  398. {
  399. double now = Scheduler::instance().clock();
  400. hdr_tcp *tcph = hdr_tcp::access(pkt);
  401. /* 
  402.  * Wouldn't it be better to set the timer *after*
  403.  * updating the RTT, instead of *before*? 
  404.  */
  405. newtimer(pkt);
  406. last_ack_ = tcph->seqno();
  407. highest_ack_ = last_ack_;
  408. if (t_seqno_ < last_ack_ + 1)
  409. t_seqno_ = last_ack_ + 1;
  410. /* 
  411.  * Update RTT only if it's OK to do so from info in the flags header.
  412.  * This is needed for protocols in which intermediate agents
  413.  * in the network intersperse acks (e.g., ack-reconstructors) for
  414.  * various reasons (without violating e2e semantics).
  415.  */
  416. hdr_flags *fh = hdr_flags::access(pkt);
  417. if (!fh->no_ts_) {
  418. if (ts_option_)
  419. rtt_update(now - tcph->ts_echo());
  420. if (rtt_active_ && tcph->seqno() >= rtt_seq_) {
  421. if (!hdr_flags::access(pkt)->ecnecho()) {
  422. /* 
  423.  * Don't end backoff if there is still an ECN-Echo
  424.  * on the packet.
  425.  */
  426. t_backoff_ = 1;
  427. }
  428. rtt_active_ = 0;
  429. if (!ts_option_)
  430. rtt_update(now - rtt_ts_);
  431. }
  432. }
  433. /* update average window */
  434. awnd_ *= 1.0 - wnd_th_;
  435. awnd_ += wnd_th_ * cwnd_;
  436. }