/* The time resolution is supposed to be 10 ns */
#include <math.h>
#include <stdio.h>
#include "../kernel/real.h"
#include "tcp.h"
/* parameters for Vegas control prtocol */
#define beta_thresh 4
/* max extrat buffers in the network (Vegas 2-4) */
#define alpha_thresh 2
/* min extrat buffers in the network
s */
#define gamma_thresh 1
/*
extra buffers at slow-start
*/
static void vegas_output ();
static void vegas_slowtimo ();
static void vegas_timers ();
static void vegas_ack ();
struct frame
{
PKT_PTR pkt;
/* in BSD, packets are queued for retransmissions (prev, next).
Here we create a packet every time we need
to retransmit it */
short nn;
int
timeout;
long last_sent;
/* seq of last pkt. sent */
long last_ack;
/* last ack recvd */
int
cur_win; /* current window size */
int
ssthresh; /* slow start threshold */
int
count; /* count of # of increments made
* to cur_window so far */
int
max_win; /* max window size allowed
*/
short mdev;
/* of rtt estimate from mean */
short rtt;
/* actually, the estimate */
short srtt;
long t_rtseq;
char back_off;
/* determines multiplier for timeout */
int
line_busy; /* respect of the interpacket
delay */
char n_retx[MAX_WINDOW];
/* number of retxs of packet i
* in cur win */
int
t_timer[MAX_TIMERS];
char t_dupacks;
/* number of dupliacte Acks seen */
char t_rexmtthresh;
/* number of duplicate Acks for retxsion */
long max_sent;
char dropped[MAX_WINDOW_SIZE];
/* parameters for Vegas */
char transmits[MAX_WINDOW];
/* largest number an acked
* segment was sent */
timev time_sent[MAX_WINDOW];
int
base_RTT; /* the smaller
round-trip-time */
/* Vegas timer stuff */
int
v_rtt;
int
v_sa;
int
v_sd;
long v_timeout;
int
v_newcwnd;
/* Stores new uninflated cwnd, used to reset cwnd later.*/
/* Exp increase every other during slow-start. */
char v_exp_inc_do;
char v_exp_inc_flag;
char v_exp_inc_isless;
/* Congestion detection (or more correctly avoidance ) variables.
* The mechanism checks once per RTT. Current RTT began
with sequence
* v_cong_detect_begseq */
char num_ack_after_retx;
/* sequence number of ack after
* retx is it
the first or second */
char v_cong_detect_do;
/* whether to do it */
long v_cong_detect_begseq;
/* When RTT began */
char v_cong_detect_predict_do;
char Transmits;
/* Whether to predict the available bw during slow-start */
long v_cong_detect_sumRTT;
/* Used to get average (avera = sumRTT/cntRTT) */
int
v_cong_detect_cntRTT;
/* number of rtt mesured during a RTT interval */
/* The congestion window should stay within band. Going above
* it means that not enough buffers are being used at the
* bottleneck, so cwnd should increase. Going below the
band means
* that too many buffers are being used, so cwnd should
decrease. */
char v_cong_detect_top_isless;
/* => cwnd < top of band */
char v_cong_detect_bot_isless;
/* => cwnd < bot of band */
int v_incr;
/* How much to increase cwnd when an ACK is received */
timev v_time_cwin_chg;
timev v_cong_detect_begtime;
timev v_cong_detect_last_sendtime;
/* Time when congestion window was last decreased. Used to prevent
*decreasing cwin more than once for losses which occurred
at the
same cwin level */
int
s_n_retx;
};
vegas()
{
/* Dummy variables for nest that we don't use. */
ident
sender, destn;
int
key;
int
i;
timev now;
struct frame f;
bzero ((char *) &f, sizeof f);
f.nn = get_node_id ();
abs_advance (node_start_time[f.nn]);
printf ("Vegas ftp source: %d ", f.nn);
printf ("sending to sink %d\n", assigned_sink[f.nn]);
source_node_type[f.nn] = FTP_SOURCE;
for (i = 0; i< MAX_TIMERS; i++)
f.t_timer[i] = 0;
f.last_sent
= -1;
f.max_sent
= -1;
f.last_ack
= -1;
f.t_rexmtthresh = 3;
f.t_dupacks
= 0;
f.num_ack_after_retx= 0;
f.max_win
= ftp_window;
f.ssthresh
= 32;
f.cur_win
= 1;
f.count
= 0;
f.mdev
= 4;
f.rtt
= 1;
f.t_rtseq
= -1;
f.srtt
= 1;
f.back_off
= 0;
f.timeout
= 2;
f.s_n_retx
= 0;
f.line_busy
= 0;
f.v_cong_detect_predict_do = 0;
f.v_exp_inc_do
= 1; /* 1 if you want to use vegas, otherwise Reno is running */
f.v_exp_inc_flag
= 1;
f.v_exp_inc_isless
= 0;
f.v_cong_detect_do
= 1; /* 1 if you want to use vegas, otherwise Reno is running */
f.v_cong_detect_begseq = -1;
(f.v_cong_detect_begtime).tv_sec = 0;
(f.v_cong_detect_begtime).tv_usec = 0;
f.base_RTT = 100000000;
f.v_cong_detect_sumRTT = 0;
f.v_cong_detect_cntRTT = 0;
f.v_cong_detect_top_isless = 0;
f.v_cong_detect_bot_isless = 0;
f.v_incr
= 0;
f.v_timeout
= 1000;
f.v_sa
= 300 << 8;
f.v_rtt = f.v_sd
= 0;
f.Transmits
= 0;
f.t_rtseq = -1;
f.back_off = 0;
f.timeout = 2;
f.t_timer[TCPT_REXMT] = f.timeout;
/* send the first packet */
(void) vegas_output (&f);
/* schedule the next software timer 500 ms */
{
PKT_PTR
tick_pkt;
float
delay;
timev
now;
now = runtime ();
hold();
tick_pkt = (PKT_PTR) malloc ((unsigned) sizeof (PKT));
release(1);
tick_pkt->source = tick_pkt->dest = f.nn;
tick_pkt->size = ftp_size;
tick_pkt->type = TICK;
delay = 0.5;
set_timer (delay, tick_pkt);
}
while (1)
{
sender = recvm (&destn, &key,
&f.pkt);
switch (f.pkt->type)
{
case ACK:
vegas_ack (&f);
break;
case INT:
hold ();
f.line_busy = 0;
free (f.pkt);
release (1);
vegas_output (&f);
break;
case TIMEOUT:
hold ();
free (f.pkt);
release (1);
break;
case TICK:
hold ();
free (f.pkt);
release (1);
vegas_slowtimo (&f);
break;
default:
hold ();
free (f.pkt);
release (1);
pr_error ("Vegas_source recvd. a vague pkt ");
break;
}
}
}
/*---------------------------------------------------------------------------*/
static void vegas_ack (fp)
struct frame *fp;
{
PKT_PTR pkt;
int
i;
long
last, cum_ack, rtt;
timev
now;
now = runtime();
pkt = fp->pkt;
last = fp->last_ack;
cum_ack = pkt->seq_no;
rtt = (long)(100000000*(make_float(now)
- make_float(fp->time_sent[cum_ack %MWS])));
hold ();
free (pkt);
release (1);
make_plot ("ack", cum_ack);
if (cum_ack == fp->last_ack) /* duplicate Ack seen */
{
if (++fp->t_dupacks > fp->t_rexmtthresh)
{
if (fp->cur_win < fp->max_win)
fp->cur_win++;
(void) vegas_output(fp);
goto drop;
}
if (fp->t_dupacks == fp->t_rexmtthresh
|| (expire(fp, cum_ack)))
{
/*
* Vegas retransmits when it receives a first or
a second dup ack
* if v_timeout has expired
*/
long oldsent
= fp->last_sent;
int old_cwnd = fp->cur_win;
int win
= min (fp->cur_win, fp->max_win);
/*
* we will check for timed out segments when
* we receive the next two non-duplicate ACKS
* (or less depending on how much is in transit)
*/
fp->num_ack_after_retx = min(2, fp->last_sent-fp->last_ack);
fp->last_sent = fp->last_ack;
fp->cur_win = 1;
if (fp->Transmits > 1)
fp->v_timeout << 1;
else
fp->v_timeout += fp->v_timeout >> 3;
/*
* If cwnd hasn't changed since the packet was sent,
* then we need to decrease it
*/
if (make_float(fp->time_sent[(fp->last_ack+1) % MWS])
>= make_float(fp->v_time_cwin_chg))
{
if (win <= 3)
win = 2;
else if (fp->Transmits > 1) /*
it is retxmd more than once */
{
fp->count = fp->count/2;
win /= 2; /* exponential decrease */
}
else{
fp->count = fp->count/4;
win = 3*win/4;
}
fp->v_newcwnd = win;
fp->t_timer[TCPT_REXMT] = 0;
fp->rtt = 0;
(void) vegas_output(fp);
fp->v_time_cwin_chg = runtime
();
fp->cur_win = fp->v_newcwnd +
fp->t_dupacks;
}
else /* no need to decrease cwnd */
{
(void) vegas_output(fp);
fp->cur_win = old_cwnd;
}
if (fp->Transmits == 1)
fp->t_dupacks = fp->t_rexmtthresh;
if ( fp->last_sent < oldsent)
fp->last_sent = oldsent ;
}
goto drop;
}
if (cum_ack < fp->last_ack)
{
fp->t_dupacks = 0;
goto drop;
}
/* ack not seen before */
if (fp->t_dupacks >= fp->t_rexmtthresh &&
fp->cur_win > fp->ssthresh)
fp->cur_win = fp->ssthresh;
fp->t_dupacks = 0;
/*
* If transmit timer is running and timed sequence
* number was acked, update smoothed round trip time.
* Since we now have an rtt measurement, cancel the
* timer backoff (cfp->, Phil Karn's retransmit alg.).
* Recompute the initial retransmit timer.
*/
if (fp->rtt && cum_ack >= fp->t_rtseq)
{
if (fp->v_timeout == 1000)
{
fp->v_rtt = rtt;
fp->v_sa = fp->v_rtt << 3;
fp->v_sd = fp->v_rtt << 1 ;
fp->v_timeout = ((fp->v_sa >> 2) +
fp->v_sd) >> 1;
}
if (fp->srtt != 0)
{
register short delta;
/*
* to the smoothing algorithm in rfc793
* with an alpha of .875
* (srtt = rtt/8 + srtt*7/8 in integers ???).
* Adjust t_rtt to origin 0.
*/
fp->rtt--;
delta = fp->rtt - (fp->srtt >> 3);
if ((fp->srtt += delta) <= 0)
fp->srtt = 1;
/*
* We accumulate a smoothed rtt variance
* (actually, a smoothed mean difference),
* then set the retransmit timer to smoothed
* rtt + 2 times the smoothed variance.
* rttvar is stored integer
* The following is equivalent
* to rfc793 smoothing with an alpha of .75
* (rttvar = rttvar*3/4 + |delta| / 4).
* This replaces rfc793's wired-in beta.
*/
if (delta < 0)
delta = -delta;
delta -= (fp->mdev >> 2);
if ((fp->mdev += delta) <= 0)
fp->mdev = 1;
} else {
/*
* No rtt measurement yet - use the
* unsmoothed rtt. Set the variance
* to half the rtt (so our first
* retransmit happens at 2*rtt)
*/
fp->srtt = fp->rtt << 3;
fp->mdev = fp->rtt << 1;
}
fp->rtt
= 0;
fp->back_off = 0;
TCPT_RANGESET(fp->timeout,
((fp->srtt >> 2) + fp->mdev) >> 1,
TCPTV_MIN, TCPTV_REXMTMAX);
}
if (cum_ack == fp->max_sent)
fp->t_timer[TCPT_REXMT] = 0;
else
fp->t_timer[TCPT_REXMT] = fp->timeout;
make_plot("timeout", fp->timeout);
for (i = 0; i <= cum_ack - last; ++i)
{
/* reset the bit anyhow */
fp->n_retx[(last + i) % MWS] = 0;
}
fp->last_ack = cum_ack;
/*
* when new data is acked, Reno increases
* its cwnd on every Ack if doing slow-start
* or on every RTT i doing congestion avoidance.
*/
if (fp->last_ack >= fp->v_cong_detect_begseq) {
int rtt1, sendEpoch, actual_rate, pred_rate, rttlen,
diff_rate, thresh_rate;
int win;
if(fp->v_cong_detect_cntRTT > 0)
rtt1 = (long) (fp->v_cong_detect_sumRTT
/ fp->v_cong_detect_cntRTT);
else
{
rtt1 = rtt;
}
fp->v_cong_detect_sumRTT = 0;
fp->v_cong_detect_cntRTT = 0;
rttlen = fp->last_sent - fp->v_cong_detect_begseq;
/*
* if there was only one packet in transit,
then update
* base_RTT
*/
if (rttlen <= 1 && rtt1 > 0)
{
fp->base_RTT = rtt1;
}
if (rtt1 > 0)
{
/*
* the rates are in pakets/sec, a time is given in 10 nsec
*/
thresh_rate = 100000000/fp->base_RTT;
actual_rate = (rttlen*100000000)/ rtt1;
pred_rate = ((fp->last_sent - fp->last_ack)*(100000000/fp->base_RTT));
diff_rate = pred_rate - actual_rate;
/* If we are currently doing slow-start */
if (fp->cur_win < fp->ssthresh)
{
/* chek if we are sending faster than available
bandwith */
if (diff_rate > gamma_thresh*thresh_rate)
fp->v_exp_inc_isless = 1;
else
fp->v_exp_inc_isless = 0;
/*
* sendEpoch is the interval of time
during which we sent
* data. during slow-start, we usually
don't send
* during the whole RTT, only during
part of beginning.
*/
sendEpoch = (int)(100000000*(make_float(fp->v_cong_detect_last_sendtime)
- make_float(fp->time_sent[fp->v_cong_detect_begseq % MWS])));
win = fp->cur_win - 1;
/*
* If we trying to predict the available
bandwith
* during slow-start
*/
if (fp->v_cong_detect_predict_do &&
sendEpoch > 0)
{
if (fp->v_exp_inc_do) {
if (fp->v_exp_inc_flag) {
if (fp->cur_win >= 8) {
fp->ssthresh = (win*rtt1)/(2*sendEpoch);
make_plot ("ssthresh", fp->ssthresh);
fp->v_cong_detect_predict_do
= 0;
}
}
else {
if (fp->cur_win >= 4){
fp->ssthresh = (win*rtt1)/(sendEpoch);
make_plot ("ssthresh", fp->ssthresh);
fp->v_cong_detect_predict_do
= 0;
}
}
}
else if (fp->cur_win >= 8){
fp->ssthresh = (win*rtt1)/(2*sendEpoch);
make_plot ("ssthresh", fp->ssthresh);
fp->v_cong_detect_predict_do = 0;
}
if (fp->ssthresh <= fp->cur_win)
fp->ssthresh = 2;
make_plot ("ssthresh", fp->ssthresh);
}
fp->v_exp_inc_flag = !fp->v_exp_inc_flag;
}
/*
* chek if we are sending too slowly (using less than
* alpha_thresh buffers 2)
*/
if (diff_rate > alpha_thresh*thresh_rate)
fp->v_cong_detect_top_isless = 1;
else
fp->v_cong_detect_top_isless = 0;
/*
* Chek if we are sending too fast (using more than
* beta_thresh-thresh worth of buffers)
*/
if (diff_rate > beta_thresh*thresh_rate)
fp->v_cong_detect_bot_isless = 1;
else
fp->v_cong_detect_bot_isless = 0;
} /* end of rtt1 > 0 */
fp->v_cong_detect_begseq = fp->last_sent + 1 ;
/*
* In vegas, the congestion avoidance mechanism
decides by how
* much data to inrease or dcrease the congestion
window. During
* slow-start, the increase only happen during
every other RTT,
* and then the increase is one segment, as
long as we have not
* overran the available bandwith (v_exp_inc_isless==0).
* If we are not doing slow-start now, then
if we need to send
* faster (top_is_less == 0) we increase it
by (1/cwnd), if
* we need to send slower, then we decrease
cwnd by one
* immediately and we don't change the cwnd
during the next RTT
*/
if (fp->cur_win < fp->ssthresh){
/* slow-start */
if (fp->v_exp_inc_do){
/* congestion avoidance during slow-start */
if (!fp->v_exp_inc_flag)
/* not increasing during this RTT */
fp->v_incr = 0;
else if (fp->v_exp_inc_isless) {
/* Going faster than avail bw, so slow down */
fp->ssthresh = 2;
make_plot ("ssthresh", fp->ssthresh);
fp->count = 7*fp->count/8;
fp->v_incr = 0;
fp->cur_win = (7*fp->cur_win/8);
if (fp->cur_win < 2)
fp->cur_win = 2;
}
else
/* increase by one with each ACK */
fp->v_incr = ftp_size;
}
else
/* not doing congestion avoidance during slow-start */
fp->v_incr = ftp_size;
}/* end of doing slow-start (cur_win<ssthresh)
*/
else {
if (fp->v_cong_detect_do) {
/* doing congestion/detection avoidance */
if (fp->v_cong_detect_bot_isless) {
/* slow down */
if (fp->cur_win < 2)
fp->cur_win = 2;
fp->cur_win -= 1;
fp->v_incr = 0;
}
else if (fp->v_cong_detect_top_isless)
/* the current rate is fine */
fp->v_incr = 0;
else
/* we can go faster */
fp->v_incr = max(ftp_size / fp->cur_win, 1);
}
else
/* Not doing congestion detection/avoidance */
fp->v_incr = max(ftp_size / fp->cur_win, 1);
}
} /* end of code done once per RTT (cum_ack > beg_seq) */
/*
* Since we set how much to increase only once per RTT,
* we need to check during slow-start if we have
* surpassed sstthresh before the RTT period is over.
*/
if (fp->v_incr == ftp_size && fp->cur_win >= fp->ssthresh)
fp->v_incr = 0;
/* increase congestion win */
fp->count += fp->v_incr;
if ((fp->count >= ftp_size) && ((fp->cur_win - (fp->last_sent
- fp->last_ack + 1)) <= 2))
{
fp->cur_win = min (fp->cur_win + 1,
fp->max_win);
fp->count -= ftp_size;
if (fp->cur_win == fp->max_win)
fp->count = 0;
}
fp->cur_win = min (fp->cur_win, fp->max_win);
/*
* Do vegas RTT stuffp-> Vegas cheks for timeout when acks
are received
* (usually duplicate acks).
*/
any_retransmission (fp, last);
/*
* transmits to the largest number of times
* an acked segment was sent.
*/
if ( (make_float(fp->time_sent[last%MWS]) !=0) && (fp->Transmits
== 1)) {
int n;
long rtt2;
/* the rtt here is given, we have not to compute
it again */
rtt2 = rtt;
fp->v_cong_detect_sumRTT += rtt2;
fp->v_cong_detect_cntRTT++;
if (rtt2 > 0) {
fp->v_rtt = rtt2;
/*
* spike_timeInc is not used
* vtcp_input.c line 1305
* the time between two packets
*/
if (fp->v_rtt < fp->base_RTT)
{
fp->base_RTT = fp->v_rtt;
}
n = fp->v_rtt - (fp->v_sa >> 3);
fp->v_sa += n;
if (n <0) n = -n;
n -= (fp->v_sd >> 2);
fp->v_sd += n;
fp->v_timeout = (((fp->v_sa >> 2) +
fp->v_sd) >> 1);
/*
* since we use more occurate time,
we need
* to make it a little bigger
*/
fp->v_timeout += (fp->v_timeout >> 4);
}/* end of if rtt2 > 0 */
}/* end of vegas stuff */
/*
* Vegas cheks for timed out segments if we receive
* a first or second no duplicate ack after retransmission
*/
fp->last_ack = cum_ack;
if (fp->last_sent < fp->last_ack)
fp->last_sent = fp->last_ack;
if (fp->num_ack_after_retx > 0)
{
fp->num_ack_after_retx--;
if (expire (fp, fp->last_ack))
{
long old_sent = fp->last_sent;
int old_cwn = fp->cur_win;
fp->t_dupacks = fp->t_rexmtthresh;
fp->last_sent = fp->last_ack;
fp->cur_win = 1;
(void) vegas_output (fp);
if (fp->last_sent < old_sent)
fp->last_sent = old_sent;
fp->cur_win = old_cwn;
goto drop;
}else
fp->num_ack_after_retx = 0;
}
(void) vegas_output (fp);
drop: ;
}
static void vegas_output (fp)
struct frame *fp;
{
PKT_PTR pkt;
int
win, nqueued;
win = min (fp->cur_win, fp->max_win);
/* Send as mutch data as we can */
if (fp->line_busy)
return;
if (fp->last_sent + 1 <= fp->last_ack + win)
{
int startseq = (++fp->last_sent);
/* ok to send now */
hold ();
pkt = (PKT_PTR) calloc (1,(unsigned)
sizeof (PKT));
release (1);
fp->pkt
= pkt;
pkt->size =
ftp_size;
pkt->gen_time = runtime ();
pkt->type =
FTP;
pkt->gs
= 0;
pkt->seq_no = max (fp->last_sent,
fp->last_ack+1);
pkt->dest = assigned_sink[fp->nn];
if (pkt->dest < ABSOLUTE_MAX_NODES)
pkt->dest += ABSOLUTE_MAX_NODES * realnum;
pkt->source = realnum * ABSOLUTE_MAX_NODES
+ fp->nn;
fp->dropped[pkt->seq_no % MAX_WINDOW_SIZE]
= 0;
fp->line_busy = 1;
if (fp->last_sent > fp->max_sent)
{
fp->max_sent = fp->last_sent;
if (fp->rtt == 0) {
fp->rtt = 1;
fp->t_rtseq = startseq;
make_plot("rt_seq", fp->t_rtseq);
}
}else
{
++fp->n_retx[fp->last_sent % MWS];
++fp->s_n_retx;
}
if (fp->t_timer[TCPT_REXMT] == 0 &&
fp->last_sent != fp->last_ack)
{
fp->t_timer[TCPT_REXMT] = fp->timeout;
fp->back_off
= 0;
}
++fp->transmits[fp->last_sent % MWS];
fp->time_sent[fp->last_sent % MWS] =
runtime();
fp->v_cong_detect_last_sendtime = runtime();
vegas_send (fp);
}
}
/*
* This routine is called every 500 ms, updates the timers
* (retransmission timer), and the round trip times.
* The fast timeout for processing delayed Acks is not used
*/
static void vegas_slowtimo (fp)
struct frame *fp;
{
if (fp->t_timer[TCPT_REXMT] && --fp->t_timer[TCPT_REXMT]
== 0)
{
/*
* when a timer expire, this routine
calls tcp_usrreq
* which determines which timer
has been timed out,
* and calls the appropriate routine.
In our case
* the only even which may happen
is the retransmission
* timer which has expired. So
tcp_timers is directly called
*/
(void) vegas_timers (fp);
}
if (fp->rtt)
fp->rtt++;
/* schedule the next software timer 500 ms */
{
PKT_PTR
tick_pkt;
float
delay;
timev
now;
now = runtime ();
hold();
tick_pkt = (PKT_PTR) malloc ((unsigned) sizeof (PKT));
release(1);
tick_pkt->source = tick_pkt->dest = fp->nn;
tick_pkt->size = ftp_size;
tick_pkt->type = TICK;
delay = 0.5;
set_timer (delay, tick_pkt);
}
}
/* TCP timeout processing */
static void vegas_timers (fp)
struct frame *fp;
{
register int rexmt;
if (++fp->back_off > TCP_MAXRXTSHIFT){
printf ("connection timed out \n");
printf("Acknowledged %ld packets\n", fp->last_ack);
exit();
}
rexmt = ((fp->srtt >> 2) + fp->mdev) >> 1;
rexmt *= tcp_backoff[fp->back_off];
TCPT_RANGESET(fp->timeout, rexmt, TCPTV_MIN, TCPTV_REXMTMAX);
fp->t_timer[TCPT_REXMT] = fp->timeout;
make_plot("timeout", fp->timeout);
/*
* If losing, let the lower level know and try for
* a better route. Also, if we backed off this far,
* our srtt estimate is probably bogus. Clobber it
* so we'll take the next rtt measurement as our srtt;
* move the current srtt into rttvar to keep the current
* retransmit times until then.
*/
if (fp->back_off > MAX_RT_SHIFT / 4)
{
fp->mdev += fp->srtt;
fp->srtt = 0;
}
fp->last_sent = fp->last_ack;
/*
* If timing a segment in this window, stop the timer.
*/
fp->rtt = 0;
/*
* Close the congestion window down to one segment
* (we'll open it by one segment for each ack we get).
* Since we probably have a window's worth of unacked
* data accumulated, this "slow start" keeps us from
* dumping all that data as back-to-back packets (which
* might overwhelm an intermediate gateway).
*
* There are two phases to the opening: Initially we
* open by one mss on each ack. This makes the window
* size increase exponentially with time. If the
* window is larger than the path can handle, this
* exponential growth results in dropped packet(s)
* almost immediately. To get more time between
* drops but still "push" the network to take advantage
* of improving conditions, we switch from exponential
* to linear window opening at some threshhold size.
* For a threshhold, we use half the current window
* size, truncated to a multiple of the mss.
*
* (the minimum cwnd that will give us exponential
* growth is 2 mss. We don't allow the threshhold
* to go below this.)
*/
{
int win = fp->cur_win / 2;
if (win < 2)
win = 2;
fp->cur_win = 1;
fp->ssthresh = win;
make_plot ("ssthresh", fp->ssthresh);
fp->t_dupacks = 0;
fp->count = 0;
}
(void) vegas_output(fp);
}
static vegas_send (fp)
struct frame *fp;
{
PKT_PTR pkt;
ident
dest;
timev
now;
ident
node_number;
int
win;
node_number = get_node_id ();
now = runtime
();
pkt = fp->pkt;
make_plot("seq", pkt->seq_no);
make_plot ("win", fp->cur_win);
dest = pkt->dest;
if ((dest / ABSOLUTE_MAX_NODES) != realnum) /* not local */
dest = cc_router;
else
dest = dest % ABSOLUTE_MAX_NODES;
pkt->timeout = (long) (200 * MILLION);
if (route[node_number][dest] == 0)
pr_error ("Routing error in Vegas_source");
if (sendm (route[node_number][dest], 0, (char *) pkt) isnt 1)
pr_error ("Vegas_safe_send: message undeliverable
", pkt);
}
int expire (fp, seq)
struct frame *fp;
int seq;
{
int len = 0;
long time;
timev now;
now = runtime();
time = 100000000*(make_float(now)- make_float(fp->time_sent[(seq
+ 1) % MWS]));
if (time >= fp->v_timeout && seq + 1 <= fp->max_sent){
len++;
fp->Transmits = fp->transmits[(seq + 1) % MWS];
}
return len;
}
any_retransmission (fp, sequence)
struct frame *fp;
int sequence;
{
int i;
fp->Transmits = 0;
for (i=1; i <= (fp->last_ack - sequence); i++)
{
fp->Transmits = max(fp->Transmits, fp->transmits[(sequence+
i)%MWS]);
fp->transmits[(sequence+ i)%MWS] = 0;
}
}