src/vfer_ccontrol.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 2005, 2006, Internet2
00003  * Legal conditions are in file LICENSE
00004  * (MD5 = c434f2e53b8089d8b4d0172c7ce07360).
00005  */
00006 /**
00007  *
00008  * @file   vfer_ccontrol.c
00009  * @author Ivan Beschastnikh
00010  * @brief  Implements congestion control hooks for control.c
00011  *
00012  * This file contains functions that are called from control.c
00013  * whenever cc needs to be done or queried for advice. For now this
00014  * file is included in control.c and all functions are inlined for
00015  * efficiency.
00016  *
00017  * -     05/28/06        ivan            Moved to use btree instead of minhist structure for delay tracking
00018  * -     03/25/06        ivan            Joined with ccontrol.h, functions renamed, delay-based cc functions created.
00019  * -     03/20-24/06     ivan            Lots of work and everything is revamped to do delay based CC
00020  * -     02/19/06        ivan            Added minhist addition of delay values
00021  * -     02/18/06        ivan            Created
00022  */
00023 
00024 #include "vfer_ccontrol.h"
00025 
00026 /**
00027  * Takes appropriate CC action after having sent a control packet
00028  *
00029  * @param p control packet
00030  * @param sock socket whose cc we are dealing with
00031  */
00032 void CC_Sent_CtlPack(packet* p, vfer_sock* sock) {
00033         sock->ccontrol.s_inflight++;
00034         sock->ccontrol.s_last_seq = sock->l_seq + 1;
00035         DEBUG_CC(DEBUG_CCTL, "ccontrol.c", "CC_Sent_CtlPack", sock);
00036 } /* CC_Sent_CtlPack() */
00037 
00038 /**
00039  * Takes appropriate CC action upon receiving a close packet
00040  *
00041  * @param p cc ack packet
00042  * @param sock socket whose cc we are dealing with
00043  */
00044 void CC_Recvd_Close(packet* p, vfer_sock* sock) {
00045         ccontrol_t* c;
00046         struct timeval tv;
00047         c = &(sock->ccontrol);
00048         GET_TIME_OF_DAY(&tv);
00049         Tree_Insert(&(c->rev_path_base_delayhist), p->delay, tv);
00050         Tree_Insert(&(c->rev_path_curr_delayhist), p->delay, tv);
00051         //sock->delay = p->delay;
00052         sock->ccontrol.r_last_seq = p->seq + 1;
00053 } /* CC_Recvd_Close() */
00054 
00055 /**
00056  * Determines if a data packet of specific size can be sent at this
00057  * time on a socket, uses byte accounting.
00058  *
00059  * @param data_size data size that control.c would like to send as a data packet
00060  * @param sock socket whose cc we are dealing with
00061  *
00062  * @return 0 if CC doesn't allow for sending of data_size bytes
00063  * @return 1 if CC does allow for sending of data_size bytes
00064  */
00065 inline int CC_Can_Send_Data(size_t data_size, vfer_sock* sock) {
00066         if ((data_size + sock->ccontrol.s_cwnd_sent) > sock->ccontrol.s_cwnd) {
00067                 return 0;
00068         }
00069         return 1;
00070 } /* CC_Can_Send_Data() */
00071 
00072 /**
00073  * Takes appropriate CC action after having sent a data packet
00074  *
00075  * @param p data packet which was sent
00076  * @param frame frame pointer of which the data packet is carrying a fragment
00077  * @param sock socket whose cc we are dealing with
00078  */
00079 inline void CC_Sent_Data(packet* p, frame_link* frame, vfer_sock* sock) {
00080         sock->ccontrol.s_cwnd_sent              += p->u.data.data_len;  /* window in byte accounting */
00081         sock->ccontrol.s_last_seq               = sock->l_seq + 1;
00082         /* s_last_unacked_data timestamp is set in control.c : ControlT */
00083         sock->ccontrol.s_last_data_frame        = frame;
00084         sock->ccontrol.s_last_data_offset       = p->u.data.data_offset;
00085         sock->ccontrol.s_inflight++;
00086 //      DEBUG_CC(DEBUG_CCTL, "ccontrol.c", "CC_Sent_Data", sock);
00087 } /* CC_Sent_Data() */
00088 
00089 /**
00090  * Takes appropriate CC action upon receiving a data packet
00091  *
00092  * @param p data packet
00093  * @param sock socket whose cc we are dealing with
00094  */
00095 void CC_Recvd_Data(packet* p, vfer_sock* sock) {
00096         ccontrol_t* c;
00097         struct timeval tv;
00098 
00099         c = &(sock->ccontrol);
00100         GET_TIME_OF_DAY(&tv);
00101         Tree_Insert(&(c->rev_path_base_delayhist), p->delay, tv);
00102         Tree_Insert(&(c->rev_path_curr_delayhist), p->delay, tv);
00103         
00104         if (p->seq >= c->r_last_seq) {
00105                 /* received a consecutive packet ; stretch the current rtt receiving window
00106                    and figure out the number of missed packets between the current boundary and the new boundary */
00107                 /* DEBUG_PRINT(DEBUG_CCTL, "ccontrol.c", "CC_Recvd_Data", "data packet [%d bytes] with future seq, expanding receiving window", p->u.data.data_len); */
00108                 c->r_packets_lost       += (p->seq - c->r_last_seq);
00109                 c->r_last_seq            = p->seq+1;
00110         } else if (p->seq >= c->r_first_seq) {
00111                 /* received a packet that was previous counted as lost
00112                    update the lost count by -1 for current rtt ; do not stretch the receiving window */
00113                 DEBUG_PRINT(DEBUG_CCTL, "ccontrol.c", "CC_Recvd_Data", "data packet [%d bytes] that was counted as lost", p->u.data.data_len);
00114                 c->r_packets_lost--;
00115         } else {
00116                 DEBUG_PRINT(DEBUG_CCTL, "ccontrol.c", "CC_Recvd_Data", "data packet from the past");
00117                 return;
00118         }
00119 
00120         c->r_bytes_total += p->u.data.data_len;
00121         c->r_unacked_bytes += p->u.data.data_len;
00122 
00123         /* DEBUG_CC(DEBUG_CCTL, "ccontrol.c", "CC_Recvd_Data", sock); */
00124 } /* CC_Recvd_Data() */
00125 
00126 
00127 /**
00128  * Takes appropriate CC action upon receiving a cc ack packet.
00129  * Currently implements a delay based CC.
00130  *
00131  * @param p cc ack packet
00132  * @param sock socket whose cc we are dealing with
00133  */
00134 void CC_Recvd_Ack(packet* p, vfer_sock* sock) {
00135         int packets_acked;
00136         int new_rtt;
00137         uint16_t packets_lost;
00138         uint32_t bytes_acked;
00139         ccontrol_t* c;
00140         struct timeval tv;
00141         double off_target;
00142         int lost;
00143         double scaled_gain;
00144 
00145         c = &(sock->ccontrol);
00146 
00147         /* make sure that this ack acknowledges a packet in our sending range */
00148         if (!((p->u.ccack.last_seq >= (c->s_first_seq - 1) &&
00149                p->u.ccack.last_seq < c->s_last_seq))) {
00150                 DEBUG_PRINT(DEBUG_CCTL, "ccontrol.c", "CC_Recvd_Ack", "ack acknowledges a packet[s] outside of current window range ; ignoring");
00151                 return;
00152         }
00153 
00154         DEBUG_PACK(DEBUG_CCTL, "ccontrol.c", "CC_Recvd_Ack", p, ":");
00155         GET_TIME_OF_DAY(&tv);
00156         Tree_Insert(&(c->rev_path_base_delayhist), p->delay, tv);
00157         Tree_Insert(&(c->rev_path_curr_delayhist), p->delay, tv);
00158 
00159         c->delay_delta          = p->u.ccack.delay_delta;
00160         c->delay                = p->u.ccack.delay;
00161 
00162         /* compute the rtt from the cc ack information and update the avg,max,min rtt stats */
00163         new_rtt = abs(p->u.ccack.delay - p->delay);
00164         if (new_rtt == 0) new_rtt = 1;
00165         sock->stats.avg_rtt = ((sock->stats.avg_rtt * sock->stats.rtt_measurements) + new_rtt) / (sock->stats.rtt_measurements + 1);
00166         if (sock->stats.max_rtt < new_rtt) sock->stats.max_rtt = new_rtt;
00167         if (sock->stats.min_rtt > new_rtt) sock->stats.min_rtt = new_rtt;
00168         sock->stats.rtt_measurements++;
00169 
00170         /* compute packet loss */
00171         if (c->last_packets_lost < p->u.ccack.packets_lost) {
00172                 packets_lost = p->u.ccack.packets_lost - c->last_packets_lost;
00173         } else {
00174                 packets_lost = 0;
00175         }
00176 
00177         /* compute packets_acked and update packet inflight */
00178         packets_acked = p->u.ccack.last_seq - c->s_first_seq + 1;
00179         if (packets_acked > c->s_inflight) {
00180                 ERROR_PRINT("ccontrol.c","CC_Recvd_Ack","packets_acked > c->s_inflight !");
00181                 c->s_inflight = 0;
00182         } else {
00183                 c->s_inflight -= packets_acked;
00184 }
00185 
00186         /* compute bytes_acked */
00187         if ((p->u.ccack.bytes_total - c->last_bytes_total) != 0) {
00188                 bytes_acked = p->u.ccack.bytes_total - c->last_bytes_total;
00189         } else {
00190                 bytes_acked = 0;
00191         }
00192 
00193         off_target = CCONTROL_TARGET - (c->delay_delta);
00194         /* GAIN = rate increase or (MAX_CWND_INCREASE_PACKETS_PER_RTT * UNACKED_THRESH * MTU * MTU) / TARGET
00195            scaled_gain = GAIN * off_target / CWND */
00196         scaled_gain = (MAX_CWND_INCREASE_PACKETS_PER_RTT * c->mtu * c->mtu * off_target * UNACKED_THRESH) / (CCONTROL_TARGET * (double)(c->s_cwnd));
00197 
00198         // printf("mtu[%d] off_target[%f] scaled_gain[%f] old_cwnd[%d]\n", c->mtu, off_target, scaled_gain, c->s_cwnd);
00199         
00200         if (scaled_gain < 0 && ((scaled_gain * -1) > c->s_cwnd)) {
00201                 c->s_cwnd = 4 * c->mtu;
00202         } else {
00203                 if (scaled_gain > c->s_maxw ||
00204                     (c->s_maxw - c->s_cwnd) < scaled_gain) {
00205                         c->s_cwnd = c->s_maxw;
00206                 } else {
00207                         c->s_cwnd += scaled_gain;
00208                 }
00209         }
00210 
00211         if (packets_lost != 0) {
00212                 lost = 0;
00213                 if (c->r_last_loss.tv_sec == 0) {
00214                         c->s_cwnd /= 2;
00215                         lost = 1;
00216                         c->r_last_loss = tv;
00217                 }
00218         }
00219 
00220         /* make sure that the congestion window is below max */
00221         if (c->s_cwnd > c->s_maxw) {
00222                 DEBUG_PRINT(DEBUG_CCTL, "ccontrol.c","CC_Recvd_Ack","cwin too large, setting to [%u]", c->s_maxw);
00223                 c->s_cwnd = c->s_maxw;
00224         }
00225 
00226         /* make sure that we don't shrink our window too small: min of 4*MSS */
00227         if (c->s_cwnd < 4 * c->mtu) {
00228                 c->s_cwnd = 4 * c->mtu;
00229         }
00230 
00231         c->last_bytes_total = p->u.ccack.bytes_total;
00232 
00233         /* update the reverse CC - this is done to track all losses*/
00234         if (p->seq >= c->r_last_seq) {
00235                 /* received a consecutive packet ; stretch the current rtt receiving window
00236                    and figure out the number of missed packets between the current boundary and the new boundary */
00237                 c->r_packets_lost       += (p->seq - c->r_last_seq);
00238                 c->r_last_seq            = p->seq+1;
00239         } else if (p->seq >= c->r_first_seq) {
00240                 /* received a packet that was previous counted as lost
00241                    update the lost count by -1 for current rtt ; do not stretch the receiving window */
00242                 DEBUG_PRINT(DEBUG_CCTL, "ccontrol.c", "CC_Recvd_Ack", "received ack previously counted as lost");
00243                 c->r_packets_lost--;
00244         }
00245 
00246         c->s_first_seq          = p->u.ccack.last_seq + 1;
00247         c->last_packets_lost    = p->u.ccack.packets_lost;
00248 
00249         /* PMTUD: determine if interval has elapsed in which PMTU should resume */
00250         if((sock->pmtu.probe_state == MTU_FOUND) 
00251                 && (sock->pmtu.search_low != (sock->pmtu.common_mtus + COMMON_MTU_MAX_INDEX)) 
00252                 && (sock->pmtu.next_probe_time <= tv.tv_sec)){
00253                         sock->pmtu.search_high = sock->pmtu.common_mtus + COMMON_MTU_MAX_INDEX;
00254                         sock->pmtu.probe_state = NO_PROBE_SENT;
00255         }
00256         
00257         DEBUG_CC(DEBUG_CCTL, "ccontrol.c", "CC_Recvd_Ack", sock);
00258         // DEBUG_CC(1, "ccontrol.c", "CC_Recvd_Ack", sock);
00259         // printf("%u\t%u\t%f\n", packets_lost, sock->ccontrol.s_cwnd, (c->delay_delta)/1000.0);
00260         return;
00261 } /* CC_Recvd_Ack() */

Generated on Tue Aug 8 16:07:18 2006 for VFER by  doxygen 1.4.7