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

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 2006-2007 by the Protocol Engineering Lab, U of Delaware
  3.  * All rights reserved.
  4.  *
  5.  * Protocol Engineering Lab web page : http://pel.cis.udel.edu/
  6.  *
  7.  * Paul D. Amer        <amer@@cis,udel,edu>
  8.  * Armando L. Caro Jr. <acaro@@cis,udel,edu>
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  *
  14.  * 1. Redistributions of source code must retain the above copyright
  15.  *    notice, this list of conditions and the following disclaimer.
  16.  *
  17.  * 2. Redistributions in binary form must reproduce the above copyright
  18.  *    notice, this list of conditions and the following disclaimer in the
  19.  *    documentation and/or other materials provided with the distribution.
  20.  *
  21.  * 3. Neither the name of the University nor of the Laboratory may be used
  22.  *    to endorse or promote products derived from this software without
  23.  *    specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. /* NewReno extension introduces a recover state variable per destination
  38.  * similar to avoid multiple cwnd cuts in a single window (ie, round
  39.  * trip). The concept is borrowed from TCP NewReno.
  40.  */
  41. #ifndef lint
  42. static const char rcsid[] =
  43. "@(#) $Header: /cvsroot/nsnam/ns-2/sctp/sctp-newreno.cc,v 1.4 2007/06/17 21:44:41 tom_henderson Exp $ (UD/PEL)";
  44. #endif
  45. #include "ip.h"
  46. #include "sctp-newreno.h"
  47. #include "flags.h"
  48. #include "random.h"
  49. #include "template.h"
  50. #include "sctpDebug.h"
  51. #ifdef DMALLOC
  52. #include "dmalloc.h"
  53. #endif
  54. #define MIN(x,y) (((x)<(y))?(x):(y))
  55. #define MAX(x,y) (((x)>(y))?(x):(y))
  56. static class NewRenoSctpClass : public TclClass 
  57. public:
  58.   NewRenoSctpClass() : TclClass("Agent/SCTP/Newreno") {}
  59.   TclObject* create(int, const char*const*) 
  60.   {
  61.     return (new NewRenoSctpAgent());
  62.   }
  63. } classSctpNewReno;
  64. NewRenoSctpAgent::NewRenoSctpAgent() : SctpAgent()
  65. {
  66. }
  67. void NewRenoSctpAgent::delay_bind_init_all()
  68. {
  69.   SctpAgent::delay_bind_init_all();
  70. }
  71. int NewRenoSctpAgent::delay_bind_dispatch(const char *cpVarName, 
  72.   const char *cpLocalName, 
  73.   TclObject *opTracer)
  74. {
  75.   return SctpAgent::delay_bind_dispatch(cpVarName, cpLocalName, opTracer);
  76. }
  77. void NewRenoSctpAgent::OptionReset()
  78. {
  79.   DBG_I(OptionReset);
  80.   uiRecover = 0;
  81.   DBG_X(OptionReset);
  82. }
  83. /* Go thru the send buffer deleting all chunks which have a tsn <= the 
  84.  * tsn parameter passed in. We assume the chunks in the rtx list are ordered by 
  85.  * their tsn value. In addtion, for each chunk deleted:
  86.  *   1. we add the chunk length to # newly acked bytes and partial bytes acked
  87.  *   2. we update round trip time if appropriate
  88.  *   3. stop the timer if the chunk's destination timer is running
  89.  */
  90. void NewRenoSctpAgent::SendBufferDequeueUpTo(u_int uiTsn)
  91. {
  92.   DBG_I(SendBufferDequeueUpTo);
  93.   Node_S *spDeleteNode = NULL;
  94.   Node_S *spCurrNode = sSendBuffer.spHead;
  95.   SctpSendBufferNode_S *spCurrNodeData = NULL;
  96.   /* Only the first TSN that is being dequeued can be used to reset the
  97.    * error cunter on a destination. Why? Well, suppose there are some
  98.    * chunks that were gap acked before the primary had errors. Then the
  99.    * gap gets filled with a retransmission using an alternate path. The
  100.    * filled gap will cause the cum ack to move past the gap acked TSNs,
  101.    * but does not mean that the they can reset the errors on the primary.
  102.    */
  103.   
  104.   uiAssocErrorCount = 0;
  105.   spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
  106.   /* trigger trace ONLY if it was previously NOT 0 */
  107.   if(spCurrNodeData->spDest->uiErrorCount != 0)
  108.     {
  109.       spCurrNodeData->spDest->uiErrorCount = 0; // clear error counter
  110.       tiErrorCount++;                          // ... and trace it too!
  111.       spCurrNodeData->spDest->eStatus = SCTP_DEST_STATUS_ACTIVE;
  112.       if(spCurrNodeData->spDest == spPrimaryDest &&
  113.  spNewTxDest != spPrimaryDest) 
  114. {
  115.   DBG_PL(SendBufferDequeueUpTo,
  116.  "primary recovered... migrating back from %p to %p"),
  117.     spNewTxDest, spPrimaryDest DBG_PR;
  118.   spNewTxDest = spPrimaryDest; // return to primary
  119. }
  120.     }
  121.   while(spCurrNode != NULL &&
  122. ((SctpSendBufferNode_S*)spCurrNode->vpData)->spChunk->uiTsn <= uiTsn)
  123.     {
  124.       spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
  125.       /* Only count this chunk as newly acked and towards partial bytes
  126.        * acked if it hasn't been gap acked or marked as ack'd due to rtx
  127.        * limit.  
  128.        */
  129.       if((spCurrNodeData->eGapAcked == FALSE) &&
  130.  (spCurrNodeData->eAdvancedAcked == FALSE) )
  131. {
  132.   // BEGIN -- NewReno changes to this function
  133.   uiHighestTsnNewlyAcked = spCurrNodeData->spChunk->uiTsn;
  134.   // END -- NewReno changes to this function
  135.   spCurrNodeData->spDest->uiNumNewlyAckedBytes 
  136.     += spCurrNodeData->spChunk->sHdr.usLength;
  137.   /* only add to partial bytes acked if we are in congestion
  138.    * avoidance mode and if there was cwnd amount of data
  139.    * outstanding on the destination (implementor's guide) 
  140.    */
  141.   if(spCurrNodeData->spDest->uiCwnd >spCurrNodeData->spDest->uiSsthresh &&
  142.      ( spCurrNodeData->spDest->uiOutstandingBytes 
  143.        >= spCurrNodeData->spDest->uiCwnd) )
  144.     {
  145.       spCurrNodeData->spDest->uiPartialBytesAcked 
  146. += spCurrNodeData->spChunk->sHdr.usLength;
  147.     }
  148. }
  149.       /* This is to ensure that Max.Burst is applied when a SACK
  150.        * acknowledges a chunk which has been fast retransmitted. If it is
  151.        * ineligible for fast rtx, that can only be because it was fast
  152.        * rtxed or it timed out. If it timed out, a burst shouldn't be
  153.        * possible, but shouldn't hurt either. The fast rtx case is what we
  154.        * are really after. This is a proposed change to RFC2960 section
  155.        * 7.2.4
  156.        */
  157.       if(spCurrNodeData->eIneligibleForFastRtx == TRUE)
  158. eApplyMaxBurst = TRUE;
  159.     
  160.       /* We update the RTT estimate if the following hold true:
  161.        *   1. RTO pending flag is set (6.3.1.C4 measured once per round trip)
  162.        *   2. Timestamp is set for this chunk (ie, we were measuring this chunk)
  163.        *   3. This chunk has not been retransmitted
  164.        *   4. This chunk has not been gap acked already 
  165.        *   5. This chunk has not been advanced acked (pr-sctp: exhausted rtxs)
  166.        */
  167.       if(spCurrNodeData->spDest->eRtoPending == TRUE &&
  168.  spCurrNodeData->dTxTimestamp > 0 &&
  169.  spCurrNodeData->iNumTxs == 1 &&
  170.  spCurrNodeData->eGapAcked == FALSE &&
  171.  spCurrNodeData->eAdvancedAcked == FALSE) 
  172. {
  173.   RttUpdate(spCurrNodeData->dTxTimestamp, spCurrNodeData->spDest);
  174.   spCurrNodeData->spDest->eRtoPending = FALSE;
  175. }
  176.       /* if there is a timer running on the chunk's destination, then stop it
  177.        */
  178.       if(spCurrNodeData->spDest->eRtxTimerIsRunning == TRUE)
  179. StopT3RtxTimer(spCurrNodeData->spDest);
  180.       spDeleteNode = spCurrNode;
  181.       spCurrNode = spCurrNode->spNext;
  182.       DeleteNode(&sSendBuffer, spDeleteNode);
  183.       spDeleteNode = NULL;
  184.     }
  185.   DBG_X(SendBufferDequeueUpTo);
  186. }
  187. /* This function is called as soon as we are done processing a SACK which 
  188.  * notifies the need of a fast rtx. Following RFC2960, we pack as many chunks
  189.  * as possible into one packet (PTMU restriction). The remaining marked packets
  190.  * are sent as soon as cwnd allows.
  191.  */
  192. void NewRenoSctpAgent::FastRtx()
  193. {
  194.   DBG_I(FastRtx);
  195.   Node_S *spCurrDestNode = NULL;
  196.   SctpDest_S *spCurrDestData = NULL;
  197.   Node_S *spCurrBuffNode = NULL;
  198.   SctpSendBufferNode_S *spCurrBuffData = NULL;
  199.   SctpSendBufferNode_S *spTailData = NULL;
  200.   /* be sure we clear all the eCcApplied flags before using them!
  201.    */
  202.   for(spCurrDestNode = sDestList.spHead;
  203.       spCurrDestNode != NULL;
  204.       spCurrDestNode = spCurrDestNode->spNext)
  205.     {
  206.       spCurrDestData = (SctpDest_S *) spCurrDestNode->vpData;
  207.       spCurrDestData->eCcApplied = FALSE;
  208.     }
  209.   
  210.   /* go thru chunks marked for rtx and cut back their ssthresh, cwnd, and
  211.    * partial bytes acked. make sure we only apply congestion control once
  212.    * per destination and once per window (ie, round-trip).
  213.    */
  214.   for(spCurrBuffNode = sSendBuffer.spHead;
  215.       spCurrBuffNode != NULL;
  216.       spCurrBuffNode = spCurrBuffNode->spNext)
  217.     {
  218.       spCurrBuffData = (SctpSendBufferNode_S *) spCurrBuffNode->vpData;
  219.       // BEGIN -- NewReno changes to this function
  220.       /* If the chunk has been either marked for rtx or advanced ack, we want
  221.        * to apply congestion control (assuming we didn't already).
  222.        *
  223.        * Why do we do it for advanced ack chunks? Well they were advanced ack'd
  224.        * because they were lost. The ONLY reason we are not fast rtxing them is
  225.        * because the chunk has run out of retransmissions (u-sctp). So we need
  226.        * to still account for the fact they were lost... so apply congestion
  227.        * control!
  228.        */
  229.       if((spCurrBuffData->eMarkedForRtx == TRUE ||
  230.   spCurrBuffData->eAdvancedAcked == TRUE) &&
  231.  spCurrBuffData->spDest->eCcApplied == FALSE &&
  232.  spCurrBuffData->spChunk->uiTsn > uiRecover)
  233.  
  234.   /* section 7.2.3 of rfc2960 (w/ implementor's guide v.02) 
  235.    */
  236.   spCurrBuffData->spDest->uiSsthresh 
  237.     = MAX(spCurrBuffData->spDest->uiCwnd/2, 2*uiMaxPayloadSize);
  238.   spCurrBuffData->spDest->uiCwnd = spCurrBuffData->spDest->uiSsthresh;
  239.   spCurrBuffData->spDest->uiPartialBytesAcked = 0; //reset
  240.   tiCwnd++; // trigger changes for trace to pick up
  241.   spCurrBuffData->spDest->eCcApplied = TRUE;
  242.   /* Set the recover variable to avoid multiple cwnd cuts for losses
  243.    * in the same window (ie, round-trip).
  244.    */
  245.   spTailData = (SctpSendBufferNode_S *) sSendBuffer.spTail->vpData;
  246.   uiRecover = spTailData->spChunk->uiTsn;
  247. }
  248.       // END -- NewReno changes to this function
  249.     }
  250.   /* possible that no chunks are pending retransmission since they could be 
  251.    * advanced ack'd 
  252.    */
  253.   if(eMarkedChunksPending == TRUE)  
  254.     RtxMarkedChunks(RTX_LIMIT_ONE_PACKET);
  255.   DBG_X(FastRtx);
  256. }
  257. /* returns a boolean of whether a fast retransmit is necessary
  258.  */
  259. Boolean_E NewRenoSctpAgent::ProcessGapAckBlocks(u_char *ucpSackChunk,
  260.  Boolean_E eNewCumAck)
  261. {
  262.   DBG_I(ProcessGapAckBlocks);
  263.   Boolean_E eFastRtxNeeded = FALSE;
  264.   u_int uiHighestTsnSacked = uiHighestTsnNewlyAcked; // NewReno changes
  265.   u_int uiStartTsn;
  266.   u_int uiEndTsn;
  267.   Node_S *spCurrNode = NULL;
  268.   SctpSendBufferNode_S *spCurrNodeData = NULL;
  269.   Node_S *spCurrDestNode = NULL;
  270.   SctpDest_S *spCurrDestNodeData = NULL;
  271.   Boolean_E eFirstOutstanding = FALSE;  
  272.   SctpSackChunk_S *spSackChunk = (SctpSackChunk_S *) ucpSackChunk;
  273.   u_short usNumGapAcksProcessed = 0;
  274.   SctpGapAckBlock_S *spCurrGapAck 
  275.     = (SctpGapAckBlock_S *) (ucpSackChunk + sizeof(SctpSackChunk_S));
  276.   DBG_PL(ProcessGapAckBlocks,"CumAck=%d"), spSackChunk->uiCumAck DBG_PR;
  277.   if(sSendBuffer.spHead == NULL) // do we have ANYTHING in the rtx buffer?
  278.     {
  279.       /* This COULD mean that this sack arrived late, and a previous one
  280.        * already cum ack'd everything. ...so, what do we do? nothing??
  281.        */
  282.     }
  283.   
  284.   else // we do have chunks in the rtx buffer
  285.     {
  286.       /* make sure we clear all the eSeenFirstOutstanding flags before
  287.        * using them!  
  288.        */
  289.       for(spCurrDestNode = sDestList.spHead;
  290.   spCurrDestNode != NULL;
  291.   spCurrDestNode = spCurrDestNode->spNext)
  292. {
  293.   spCurrDestNodeData = (SctpDest_S *) spCurrDestNode->vpData;
  294.   spCurrDestNodeData->eSeenFirstOutstanding = FALSE;
  295. }
  296.       for(spCurrNode = sSendBuffer.spHead;
  297.   (spCurrNode != NULL) &&
  298.     (usNumGapAcksProcessed != spSackChunk->usNumGapAckBlocks);
  299.   spCurrNode = spCurrNode->spNext)
  300. {
  301.   spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
  302.   DBG_PL(ProcessGapAckBlocks, "eSeenFirstOutstanding=%s"),
  303.     spCurrNodeData->spDest->eSeenFirstOutstanding ? "TRUE" : "FALSE"
  304.     DBG_PR;
  305.  
  306.   /* is this chunk the first outstanding on its destination?
  307.    */
  308.   if(spCurrNodeData->spDest->eSeenFirstOutstanding == FALSE &&
  309.      spCurrNodeData->eGapAcked == FALSE &&
  310.      spCurrNodeData->eAdvancedAcked == FALSE)
  311.     {
  312.       /* yes, it is the first!
  313.        */
  314.       eFirstOutstanding = TRUE;
  315.       spCurrNodeData->spDest->eSeenFirstOutstanding = TRUE;
  316.     }
  317.   else
  318.     {
  319.       /* nope, not the first...
  320.        */
  321.       eFirstOutstanding = FALSE;
  322.     }
  323.   DBG_PL(ProcessGapAckBlocks, "eFirstOutstanding=%s"),
  324.     eFirstOutstanding ? "TRUE" : "FALSE" DBG_PR;
  325.   DBG_PL(ProcessGapAckBlocks, "--> rtx list chunk begin") DBG_PR;
  326.   DBG_PL(ProcessGapAckBlocks, "    TSN=%d"), 
  327.     spCurrNodeData->spChunk->uiTsn 
  328.     DBG_PR;
  329.   DBG_PL(ProcessGapAckBlocks, "    %s=%s %s=%s"),
  330.     "eGapAcked", 
  331.     spCurrNodeData->eGapAcked ? "TRUE" : "FALSE",
  332.     "eAddedToPartialBytesAcked",
  333.     spCurrNodeData->eAddedToPartialBytesAcked ? "TRUE" : "FALSE" 
  334.     DBG_PR;
  335.   DBG_PL(ProcessGapAckBlocks, "    NumMissingReports=%d NumTxs=%d"),
  336.     spCurrNodeData->iNumMissingReports, 
  337.     spCurrNodeData->iNumTxs 
  338.     DBG_PR;
  339.   DBG_PL(ProcessGapAckBlocks, "<-- rtx list chunk end") DBG_PR;
  340.   
  341.   DBG_PL(ProcessGapAckBlocks,"GapAckBlock StartOffset=%d EndOffset=%d"),
  342.     spCurrGapAck->usStartOffset, spCurrGapAck->usEndOffset DBG_PR;
  343.   uiStartTsn = spSackChunk->uiCumAck + spCurrGapAck->usStartOffset;
  344.   uiEndTsn = spSackChunk->uiCumAck + spCurrGapAck->usEndOffset;
  345.   
  346.   DBG_PL(ProcessGapAckBlocks, "GapAckBlock StartTsn=%d EndTsn=%d"),
  347.     uiStartTsn, uiEndTsn DBG_PR;
  348.   if(spCurrNodeData->spChunk->uiTsn < uiStartTsn)
  349.     {
  350.       /* This chunk is NOT being acked and is missing at the receiver
  351.        */
  352.       /* If this chunk was GapAcked before, then either the
  353.        * receiver has renegged the chunk (which our simulation
  354.        * doesn't do) or this SACK is arriving out of order.
  355.        */
  356.       if(spCurrNodeData->eGapAcked == TRUE)
  357. {
  358.   DBG_PL(ProcessGapAckBlocks, 
  359.  "out of order SACK? setting TSN=%d eGapAcked=FALSE"),
  360.     spCurrNodeData->spChunk->uiTsn DBG_PR;
  361.   spCurrNodeData->eGapAcked = FALSE;
  362.   spCurrNodeData->spDest->uiOutstandingBytes 
  363.     += spCurrNodeData->spChunk->sHdr.usLength;
  364.   /* section 6.3.2.R4 says that we should restart the
  365.    * T3-rtx timer here if it isn't running already. In our
  366.    * implementation, it isn't necessary since
  367.    * ProcessSackChunk will restart the timer for any
  368.    * destinations which have outstanding data and don't
  369.    * have a timer running.
  370.    */
  371. }
  372.     }
  373.   else if((uiStartTsn <= spCurrNodeData->spChunk->uiTsn) && 
  374.   (spCurrNodeData->spChunk->uiTsn <= uiEndTsn) )
  375.     {
  376.       /* This chunk is being acked via a gap ack block
  377.        */
  378.       DBG_PL(ProcessGapAckBlocks, "gap ack acks this chunk: %s%s"),
  379. "eGapAcked=",
  380. spCurrNodeData->eGapAcked ? "TRUE" : "FALSE" 
  381. DBG_PR;
  382.       // BEGIN -- NewReno changes to this function
  383.       /* modified HTNA algorithm... we need to know the highest TSN
  384.        * sacked (even if it isn't new), so that when the sender
  385.        * is in Fast Recovery, the outstanding tsns beyond the 
  386.        * last sack tsn do not have their missing reports incremented
  387.        */
  388.       if(uiHighestTsnSacked < spCurrNodeData->spChunk->uiTsn)
  389. uiHighestTsnSacked = spCurrNodeData->spChunk->uiTsn;
  390.       // END -- NewReno changes to this function
  391.       if(spCurrNodeData->eGapAcked == FALSE)
  392. {
  393.   DBG_PL(ProcessGapAckBlocks, "setting eGapAcked=TRUE") DBG_PR;
  394.   spCurrNodeData->eGapAcked = TRUE;
  395.   spCurrNodeData->eMarkedForRtx = FALSE; // unmark
  396.   /* HTNA algorithm... we need to know the highest TSN
  397.    * newly acked
  398.    */
  399.   if(uiHighestTsnNewlyAcked < spCurrNodeData->spChunk->uiTsn)
  400.     uiHighestTsnNewlyAcked = spCurrNodeData->spChunk->uiTsn;
  401.   if(spCurrNodeData->eAdvancedAcked == FALSE)
  402.     {
  403.       spCurrNodeData->spDest->uiNumNewlyAckedBytes 
  404. += spCurrNodeData->spChunk->sHdr.usLength;
  405.     }
  406.   
  407.   /* only increment partial bytes acked if we are in
  408.    * congestion avoidance mode, we have a new cum ack, and
  409.    * we haven't already incremented it for this TSN
  410.    */
  411.   if(( spCurrNodeData->spDest->uiCwnd 
  412.        > spCurrNodeData->spDest->uiSsthresh) &&
  413.      eNewCumAck == TRUE &&
  414.      spCurrNodeData->eAddedToPartialBytesAcked == FALSE)
  415.     {
  416.       DBG_PL(ProcessGapAckBlocks, 
  417.      "setting eAddedToPartiallyBytesAcked=TRUE") DBG_PR;
  418.       
  419.       spCurrNodeData->eAddedToPartialBytesAcked = TRUE; // set
  420.       spCurrNodeData->spDest->uiPartialBytesAcked 
  421. += spCurrNodeData->spChunk->sHdr.usLength;
  422.     }
  423.   /* We update the RTT estimate if the following hold true:
  424.    *   1. RTO pending flag is set (6.3.1.C4)
  425.    *   2. Timestamp is set for this chunk 
  426.    *   3. This chunk has not been retransmitted
  427.    *   4. This chunk has not been gap acked already 
  428.    *   5. This chunk has not been advanced acked (pr-sctp)
  429.    */
  430.   if(spCurrNodeData->spDest->eRtoPending == TRUE &&
  431.      spCurrNodeData->dTxTimestamp > 0 &&
  432.      spCurrNodeData->iNumTxs == 1 &&
  433.      spCurrNodeData->eAdvancedAcked == FALSE) 
  434.     {
  435.       RttUpdate(spCurrNodeData->dTxTimestamp, 
  436. spCurrNodeData->spDest);
  437.       spCurrNodeData->spDest->eRtoPending = FALSE;
  438.     }
  439.   /* section 6.3.2.R3 - Stop the timer if this is the
  440.    * first outstanding for this destination (note: it may
  441.    * have already been stopped if there was a new cum
  442.    * ack). If there are still outstanding bytes on this
  443.    * destination, we'll restart the timer later in
  444.    * ProcessSackChunk() 
  445.    */
  446.   if(eFirstOutstanding == TRUE 
  447.      && spCurrNodeData->spDest->eRtxTimerIsRunning == TRUE)
  448.     StopT3RtxTimer(spCurrNodeData->spDest);
  449.   
  450.   uiAssocErrorCount = 0;
  451.   
  452.   /* trigger trace ONLY if it was previously NOT 0
  453.    */
  454.   if(spCurrNodeData->spDest->uiErrorCount != 0)
  455.     {
  456.       spCurrNodeData->spDest->uiErrorCount = 0; // clear errors
  457.       tiErrorCount++;                       // ... and trace it!
  458.       spCurrNodeData->spDest->eStatus = SCTP_DEST_STATUS_ACTIVE;
  459.       if(spCurrNodeData->spDest == spPrimaryDest &&
  460.  spNewTxDest != spPrimaryDest) 
  461. {
  462.   DBG_PL(ProcessGapAckBlocks,
  463.  "primary recovered... "
  464.  "migrating back from %p to %p"),
  465.     spNewTxDest, spPrimaryDest DBG_PR;
  466.   spNewTxDest = spPrimaryDest; // return to primary
  467. }
  468.     }
  469. }
  470.     }
  471.   else if(spCurrNodeData->spChunk->uiTsn > uiEndTsn)
  472.     {
  473.       /* This point in the rtx buffer is already past the tsns which are
  474.        * being acked by this gap ack block.  
  475.        */
  476.       usNumGapAcksProcessed++; 
  477.       /* Did we process all the gap ack blocks?
  478.        */
  479.       if(usNumGapAcksProcessed != spSackChunk->usNumGapAckBlocks)
  480. {
  481.   DBG_PL(ProcessGapAckBlocks, "jump to next gap ack block") 
  482.     DBG_PR;
  483.   spCurrGapAck 
  484.     = ((SctpGapAckBlock_S *)
  485.        (ucpSackChunk + sizeof(SctpSackChunk_S)
  486. + (usNumGapAcksProcessed * sizeof(SctpGapAckBlock_S))));
  487. }
  488.       /* If this chunk was GapAcked before, then either the
  489.        * receiver has renegged the chunk (which our simulation
  490.        * doesn't do) or this SACK is arriving out of order.
  491.        */
  492.       if(spCurrNodeData->eGapAcked == TRUE)
  493. {
  494.   DBG_PL(ProcessGapAckBlocks, 
  495.  "out of order SACK? setting TSN=%d eGapAcked=FALSE"),
  496.     spCurrNodeData->spChunk->uiTsn DBG_PR;
  497.   spCurrNodeData->eGapAcked = FALSE;
  498.   spCurrNodeData->spDest->uiOutstandingBytes 
  499.     += spCurrNodeData->spChunk->sHdr.usLength;
  500.   
  501.   /* section 6.3.2.R4 says that we should restart the
  502.    * T3-rtx timer here if it isn't running already. In our
  503.    * implementation, it isn't necessary since
  504.    * ProcessSackChunk will restart the timer for any
  505.    * destinations which have outstanding data and don't
  506.    * have a timer running.
  507.    */
  508. }
  509.     }
  510. }
  511.       /* By this time, either we have run through the entire send buffer or we
  512.        * have run out of gap ack blocks. In the case that we have run out of gap
  513.        * ack blocks before we finished running through the send buffer, we need
  514.        * to mark the remaining chunks in the send buffer as eGapAcked=FALSE.
  515.        * This final marking needs to be done, because we only trust gap ack info
  516.        * from the last SACK. Otherwise, renegging (which we don't do) or out of
  517.        * order SACKs would give the sender an incorrect view of the peer's rwnd.
  518.        */
  519.       for(; spCurrNode != NULL; spCurrNode = spCurrNode->spNext)
  520. {
  521.   /* This chunk is NOT being acked and is missing at the receiver
  522.    */
  523.   spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
  524.   /* If this chunk was GapAcked before, then either the
  525.    * receiver has renegged the chunk (which our simulation
  526.    * doesn't do) or this SACK is arriving out of order.
  527.    */
  528.   if(spCurrNodeData->eGapAcked == TRUE)
  529.   {
  530.   DBG_PL(ProcessGapAckBlocks, 
  531.  "out of order SACK? setting TSN=%d eGapAcked=FALSE"),
  532.   spCurrNodeData->spChunk->uiTsn DBG_PR;
  533.   spCurrNodeData->eGapAcked = FALSE;
  534.   spCurrNodeData->spDest->uiOutstandingBytes 
  535.   += spCurrNodeData->spChunk->sHdr.usLength;
  536.   
  537.       /* section 6.3.2.R4 says that we should restart the T3-rtx
  538.        * timer here if it isn't running already. In our
  539.        * implementation, it isn't necessary since ProcessSackChunk
  540.        * will restart the timer for any destinations which have
  541.        * outstanding data and don't have a timer running.
  542.        */
  543.   }
  544. }
  545.       DBG_PL(ProcessGapAckBlocks, "now incrementing missing reports...") DBG_PR;
  546.       DBG_PL(ProcessGapAckBlocks, "uiHighestTsnNewlyAcked=%d"), 
  547.      uiHighestTsnNewlyAcked DBG_PR;
  548.       for(spCurrNode = sSendBuffer.spHead;
  549.   spCurrNode != NULL; 
  550.   spCurrNode = spCurrNode->spNext)
  551. {
  552.   spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
  553.   DBG_PL(ProcessGapAckBlocks, "TSN=%d eGapAcked=%s"), 
  554.     spCurrNodeData->spChunk->uiTsn,
  555.     spCurrNodeData->eGapAcked ? "TRUE" : "FALSE"
  556.     DBG_PR;
  557.   if(spCurrNodeData->eGapAcked == FALSE)
  558.     {
  559.       // BEGIN -- NewReno changes to this function
  560.       /* HTNA (Highest TSN Newly Acked) algorithm from
  561.        * implementer' guide
  562.        *
  563.        * NewReno modifies HTNA to also increment the missing reports 
  564.        * when the sender is in Fast Recovery, the cum ack changes, and
  565.        * the new cum ack is less than recover.
  566.        */
  567.       if( (spCurrNodeData->spChunk->uiTsn < uiHighestTsnNewlyAcked) ||
  568.   (eNewCumAck == TRUE && 
  569.    uiHighestTsnNewlyAcked <= uiRecover &&
  570.    spCurrNodeData->spChunk->uiTsn < uiHighestTsnSacked))
  571. {
  572.   spCurrNodeData->iNumMissingReports++;
  573.   DBG_PL(ProcessGapAckBlocks, 
  574.  "incrementing missing report for TSN=%d to %d"), 
  575.     spCurrNodeData->spChunk->uiTsn,
  576.     spCurrNodeData->iNumMissingReports
  577.     DBG_PR;
  578.   if(spCurrNodeData->iNumMissingReports >= FAST_RTX_TRIGGER &&
  579.      spCurrNodeData->eIneligibleForFastRtx == FALSE &&
  580.      spCurrNodeData->eAdvancedAcked == FALSE)
  581.     {
  582.       MarkChunkForRtx(spCurrNodeData);
  583.       eFastRtxNeeded = TRUE;
  584.       spCurrNodeData->eIneligibleForFastRtx = TRUE;
  585.       DBG_PL(ProcessGapAckBlocks, 
  586.      "setting eFastRtxNeeded = TRUE") DBG_PR;
  587.     }
  588. }
  589.       // END -- NewReno changes to this function
  590.     }
  591. }
  592.     }
  593.   DBG_PL(ProcessGapAckBlocks, "eFastRtxNeeded=%s"), 
  594.     eFastRtxNeeded ? "TRUE" : "FALSE" DBG_PR;
  595.   DBG_X(ProcessGapAckBlocks);
  596.   return eFastRtxNeeded;
  597. }
  598. void NewRenoSctpAgent::ProcessSackChunk(u_char *ucpSackChunk)
  599. {
  600.   DBG_I(ProcessSackChunk);
  601.   SctpSackChunk_S *spSackChunk = (SctpSackChunk_S *) ucpSackChunk;
  602.   DBG_PL(ProcessSackChunk, "cum=%d arwnd=%d #gapacks=%d #duptsns=%d"),
  603.     spSackChunk->uiCumAck, spSackChunk->uiArwnd, 
  604.     spSackChunk->usNumGapAckBlocks, spSackChunk->usNumDupTsns 
  605.     DBG_PR;
  606.   Boolean_E eFastRtxNeeded = FALSE;
  607.   Boolean_E eNewCumAck = FALSE;
  608.   Node_S *spCurrDestNode = NULL;
  609.   SctpDest_S *spCurrDestNodeData = NULL;
  610.   u_int uiTotalOutstanding = 0;
  611.   int i = 0;
  612.   /* make sure we clear all the uiNumNewlyAckedBytes before using them!
  613.    */
  614.   for(spCurrDestNode = sDestList.spHead;
  615.       spCurrDestNode != NULL;
  616.       spCurrDestNode = spCurrDestNode->spNext)
  617.     {
  618.       spCurrDestNodeData = (SctpDest_S *) spCurrDestNode->vpData;
  619.       spCurrDestNodeData->uiNumNewlyAckedBytes = 0;
  620.       spCurrDestNodeData->eSeenFirstOutstanding = FALSE;
  621.     }
  622.   if(spSackChunk->uiCumAck < uiCumAckPoint) 
  623.     {
  624.       /* this cumAck's a previously cumAck'd tsn (ie, it's out of order!)
  625.        * ...so ignore!
  626.        */
  627.       DBG_PL(ProcessSackChunk, "ignoring out of order sack!") DBG_PR;
  628.       DBG_X(ProcessSackChunk);
  629.       return;
  630.     }
  631.   else if(spSackChunk->uiCumAck > uiCumAckPoint)
  632.     {
  633.       eNewCumAck = TRUE; // incomding SACK's cum ack advances the cum ack point
  634.       SendBufferDequeueUpTo(spSackChunk->uiCumAck);
  635.       uiCumAckPoint = spSackChunk->uiCumAck; // Advance the cumAck pointer
  636.     }
  637.   if(spSackChunk->usNumGapAckBlocks != 0) // are there any gaps??
  638.     {
  639.       eFastRtxNeeded = ProcessGapAckBlocks(ucpSackChunk, eNewCumAck);
  640.     } 
  641.   for(spCurrDestNode = sDestList.spHead;
  642.       spCurrDestNode != NULL;
  643.       spCurrDestNode = spCurrDestNode->spNext)
  644.     {
  645.       spCurrDestNodeData = (SctpDest_S *) spCurrDestNode->vpData;
  646.       // BEGIN -- NewReno changes to this function
  647.       /* Only adjust cwnd if:
  648.        *    1. sack advanced the cum ack point 
  649.        *    2. this destination has newly acked bytes
  650.        *    3. the cum ack is at or beyond the recovery window
  651.        *
  652.        * Also, we MUST adjust our congestion window BEFORE we update the
  653.        * number of outstanding bytes to reflect the newly acked bytes in
  654.        * received SACK.
  655.        */
  656.       if(eNewCumAck == TRUE &&
  657.  spCurrDestNodeData->uiNumNewlyAckedBytes > 0 &&
  658.  spSackChunk->uiCumAck >= uiRecover)
  659. {
  660.   AdjustCwnd(spCurrDestNodeData);
  661. }
  662.       // END -- NewReno changes to this function
  663.       /* The number of outstanding bytes is reduced by how many bytes this sack 
  664.        * acknowledges.
  665.        */
  666.       if(spCurrDestNodeData->uiNumNewlyAckedBytes <=
  667.  spCurrDestNodeData->uiOutstandingBytes)
  668. {
  669.   spCurrDestNodeData->uiOutstandingBytes 
  670.     -= spCurrDestNodeData->uiNumNewlyAckedBytes;
  671. }
  672.       else
  673. spCurrDestNodeData->uiOutstandingBytes = 0;
  674.       DBG_PL(ProcessSackChunk,"Dest #%d (%d:%d) (%p): outstanding=%d, cwnd=%d"),
  675. ++i, spCurrDestNodeData->iNsAddr, spCurrDestNodeData->iNsPort,
  676. spCurrDestNodeData, spCurrDestNodeData->uiOutstandingBytes, 
  677. spCurrDestNodeData->uiCwnd DBG_PR;
  678.       if(spCurrDestNodeData->uiOutstandingBytes == 0)
  679. {
  680.   /* All outstanding data has been acked
  681.    */
  682.   spCurrDestNodeData->uiPartialBytesAcked = 0;  // section 7.2.2
  683.   /* section 6.3.2.R2
  684.    */
  685.   if(spCurrDestNodeData->eRtxTimerIsRunning == TRUE)
  686.     {
  687.       DBG_PL(ProcessSackChunk, "Dest #%d (%p): stopping timer"), 
  688. i, spCurrDestNodeData DBG_PR;
  689.       StopT3RtxTimer(spCurrDestNodeData);
  690.     }
  691. }
  692.       /* section 6.3.2.R3 - Restart timers for destinations that have
  693.        * acknowledged their first outstanding (ie, no timer running) and
  694.        * still have outstanding data in flight.  
  695.        */
  696.       if(spCurrDestNodeData->uiOutstandingBytes > 0 &&
  697.  spCurrDestNodeData->eRtxTimerIsRunning == FALSE)
  698. {
  699.   StartT3RtxTimer(spCurrDestNodeData);
  700. }
  701.     }
  702.   DBG_F(ProcessSackChunk, DumpSendBuffer());
  703.   AdvancePeerAckPoint();
  704.   if(eFastRtxNeeded == TRUE)  // section 7.2.4
  705.     FastRtx();
  706.   /* Let's see if after process this sack, there are still any chunks
  707.    * pending... If so, rtx all allowed by cwnd.
  708.    */
  709.   else if( (eMarkedChunksPending = AnyMarkedChunks()) == TRUE)
  710.     {
  711.       /* section 6.1.C) When the time comes for the sender to
  712.        * transmit, before sending new DATA chunks, the sender MUST
  713.        * first transmit any outstanding DATA chunks which are marked
  714.        * for retransmission (limited by the current cwnd).  
  715.        */
  716.       RtxMarkedChunks(RTX_LIMIT_CWND);
  717.     }
  718.   /* (6.2.1.D.ii) Adjust PeerRwnd based on total oustanding bytes on all
  719.    * destinations. We need to this adjustment after any
  720.    * retransmissions. Otherwise the sender's view of the peer rwnd will be
  721.    * off, because the number outstanding increases again once a marked
  722.    * chunk gets retransmitted (when marked, outstanding is decreased).
  723.    */
  724.   uiTotalOutstanding = TotalOutstanding();
  725.   if(uiTotalOutstanding <= spSackChunk->uiArwnd)
  726.     uiPeerRwnd = (spSackChunk->uiArwnd  - uiTotalOutstanding);
  727.   else
  728.     uiPeerRwnd = 0;
  729.   
  730.   DBG_PL(ProcessSackChunk, "uiPeerRwnd=%d, uiArwnd=%d"), uiPeerRwnd, 
  731.     spSackChunk->uiArwnd DBG_PR;
  732.   DBG_X(ProcessSackChunk);
  733. }