struct vegas { u32 beg_snd_nxt; /\* right edge during last RTT \*/ u32 beg_snd_una; /\* left edge during last RTT \*/ u32 beg_snd_cwnd; /\* saves the size of the cwnd \*/ u8 doing_vegas_now;/\* if true, do vegas for this RTT \*/ u16 cntRTT; /\* # of RTTs measured within last RTT \*/ u32 minRTT; /\* min of RTTs measured within last RTT (in usec) \*/ u32 baseRTT; /\* the min of all Vegas RTT measurements seen (in usec) \*/ };
/\* Never allow zero rtt or baseRTT \*/ vrtt = rtt_us + 1;
/\* Filter to find propagation delay: \*/ if (vrtt < vegas->baseRTT) vegas->baseRTT = vrtt;
/* Find the min RTT during the last RTT to find * the current prop. delay + queuing delay: */ vegas->minRTT = min(vegas->minRTT, vrtt); vegas->cntRTT++; }
if (!vegas->doing_vegas_now) { tcp_reno_cong_avoid(sk, ack, in_flight); return; } //判断ack,也就是上次采样标记之后的数据全部ack之后,才会进入vegas算法.
if (after(ack, vegas->beg_snd_nxt)) { /\* Do the Vegas once-per-RTT cwnd adjustment. \*/
/* Save the extent of the current window so we can use this * at the end of the next RTT. */ vegas->beg_snd_nxt = tp->snd_nxt;
/* We do the Vegas calculations only if we got enough RTT * samples that we can be reasonably sure that we got * at least one RTT sample that wasn’t from a delayed ACK. * If we only had 2 samples total, * then that means we’re getting only 1 ACK per RTT, which * means they’re almost certainly delayed ACKs. * If we have 3 samples, we should be OK. */
if (vegas->cntRTT <= 2) { /* We don’t have enough RTT samples to do the Vegas * calculation, so we’ll behave like Reno. */ tcp_reno_cong_avoid(sk, ack, in_flight); } else { u32 rtt, diff; u64 target_cwnd;
/* We have enough RTT samples, so, using the Vegas * algorithm, we determine if we should increase or * decrease cwnd, and by how much. */
/* Pluck out the RTT we are using for the Vegas * calculations. This is the min RTT seen during the * last RTT. Taking the min filters out the effects * of delayed ACKs, at the cost of noticing congestion * a bit later. */ rtt = vegas->minRTT;
/* Calculate the cwnd we should have, if we weren’t * going too fast. * * This is: \* (actual rate in segments) \* baseRTT */ //计算下次应该的窗口 target_cwnd = tp->snd_cwnd * vegas->baseRTT / rtt;
/* Calculate the difference between the window we had, * and the window we would like to have. This quantity * is the "Diff" from the Arizona Vegas papers. */ //计算窗口的变化差 diff = tp->snd_cwnd * (rtt-vegas->baseRTT) / vegas->baseRTT; //如果变化太大(适用于slow start),则减小窗口 if (diff > gamma && tp->snd_cwnd <= tp->snd_ssthresh) { /* Going too fast. Time to slow down * and switch to congestion avoidance. */
/* Set cwnd to match the actual rate * exactly: \* cwnd = (actual rate) \* baseRTT * Then we add 1 because the integer * truncation robs us of full link * utilization. */ tp->snd_cwnd = min(tp->snd_cwnd, (u32)target_cwnd+1); tp->snd_ssthresh = tcp_vegas_ssthresh(tp);
/* Figure out where we would like cwnd * to be. */ if (diff > beta) { /* The old window was too fast, so * we slow down. */ //发送太快,因此减速 tp->snd_cwnd–; tp->snd_ssthresh = tcp_vegas_ssthresh(tp); } else if (diff < alpha) { /* We don’t have enough extra packets * in the network, so speed up. */ //网络中包太少,因此加速 tp->snd_cwnd++; } else { /* Sending just as fast as we * should be. */ } }
if (tp->snd_cwnd < 2) tp->snd_cwnd = 2; else if (tp->snd_cwnd > tp->snd_cwnd_clamp) tp->snd_cwnd = tp->snd_cwnd_clamp;
tp->snd_ssthresh = tcp_current_ssthresh(sk); } //重置cntRTT和minRTT /\* Wipe the slate clean for the next RTT. \*/ vegas->cntRTT = 0; vegas->minRTT = 0x7fffffff; } /\* Use normal slow start \*/ else if (tp->snd_cwnd <= tp->snd_ssthresh) tcp_slow_start(tp);