/*
* send_control.cpp
- * p2tp
+ * congestion control logic for the swift protocol
*
* Created by Victor Grishchenko on 12/10/09.
* Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
-#include "p2tp.h"
+#include "swift.h"
-using namespace p2tp;
+using namespace swift;
using namespace std;
tint Channel::MIN_DEV = 50*TINT_MSEC;
tint Channel::LEDBAT_TARGET = TINT_MSEC*25;
float Channel::LEDBAT_GAIN = 1.0/LEDBAT_TARGET;
tint Channel::LEDBAT_DELAY_BIN = TINT_SEC*30;
+tint Channel::MAX_POSSIBLE_RTT = TINT_SEC*10;
const char* Channel::SEND_CONTROL_MODES[] = {"keepalive", "pingpong",
- "slowstart", "standard_aimd", "ledbat"};
+ "slowstart", "standard_aimd", "ledbat", "closing"};
tint Channel::NextSendTime () {
+ TimeoutDataOut(); // precaution to know free cwnd
switch (send_control_) {
case KEEP_ALIVE_CONTROL: return KeepAliveNextSendTime();
case PING_PONG_CONTROL: return PingPongNextSendTime();
case SLOW_START_CONTROL: return SlowStartNextSendTime();
case AIMD_CONTROL: return AimdNextSendTime();
case LEDBAT_CONTROL: return LedbatNextSendTime();
+ case CLOSE_CONTROL: return TINT_NEVER;
default: assert(false);
}
}
tint Channel::SwitchSendControl (int control_mode) {
- dprintf("%s #%u sendctrl %i->%i\n",tintstr(),id,send_control_,control_mode);
+ dprintf("%s #%u sendctrl switch %s->%s\n",tintstr(),id(),
+ SEND_CONTROL_MODES[send_control_],SEND_CONTROL_MODES[control_mode]);
switch (control_mode) {
case KEEP_ALIVE_CONTROL:
- send_interval_ = max(TINT_SEC/10,rtt_avg_);
+ send_interval_ = rtt_avg_; //max(TINT_SEC/10,rtt_avg_);
dev_avg_ = max(TINT_SEC,rtt_avg_);
+ data_out_cap_ = bin64_t::ALL;
cwnd_ = 1;
break;
case PING_PONG_CONTROL:
dev_avg_ = max(TINT_SEC,rtt_avg_);
+ data_out_cap_ = bin64_t::ALL;
cwnd_ = 1;
break;
case SLOW_START_CONTROL:
+ cwnd_ = 1;
break;
case AIMD_CONTROL:
break;
case LEDBAT_CONTROL:
break;
+ case CLOSE_CONTROL:
+ break;
default:
assert(false);
}
return NextSendTime();
}
-// TODO: transitions, consistently
-// TODO: may send data
tint Channel::KeepAliveNextSendTime () {
if (sent_since_recv_>=3 && last_recv_time_<NOW-TINT_MIN)
- return TINT_NEVER;
+ return SwitchSendControl(CLOSE_CONTROL);
if (ack_rcvd_recent_)
return SwitchSendControl(SLOW_START_CONTROL);
- if (data_in_.bin!=bin64_t::NONE)
+ if (data_in_.time!=TINT_NEVER)
return NOW;
- send_interval_ <<= 1;
+ if (last_send_time_==NOW)
+ send_interval_ <<= 1;
if (send_interval_>MAX_SEND_INTERVAL)
send_interval_ = MAX_SEND_INTERVAL;
return last_send_time_ + send_interval_;
}
tint Channel::PingPongNextSendTime () { // FIXME INFINITE LOOP
- if (last_recv_time_ < last_send_time_-TINT_SEC*3) {
- // FIXME keepalive <-> pingpong (peers, transition)
- } // last_data_out_time_ < last_send_time_ - TINT_SEC...
- if (false)
+ if (dgrams_sent_>=10)
return SwitchSendControl(KEEP_ALIVE_CONTROL);
if (ack_rcvd_recent_)
return SwitchSendControl(SLOW_START_CONTROL);
- if (data_in_.bin!=bin64_t::NONE)
+ if (data_in_.time!=TINT_NEVER)
return NOW;
if (last_recv_time_>last_send_time_)
return NOW;
- else if (last_send_time_)
- return last_send_time_ + ack_timeout();
- else
+ if (!last_send_time_)
return NOW;
+ return last_send_time_ + ack_timeout(); // timeout
}
tint Channel::CwndRateNextSendTime () {
- if (data_in_.bin!=bin64_t::NONE)
+ if (data_in_.time!=TINT_NEVER)
return NOW; // TODO: delayed ACKs
+ //if (last_recv_time_<NOW-rtt_avg_*4)
+ // return SwitchSendControl(KEEP_ALIVE_CONTROL);
send_interval_ = rtt_avg_/cwnd_;
+ if (send_interval_>max(rtt_avg_,TINT_SEC)*4)
+ return SwitchSendControl(KEEP_ALIVE_CONTROL);
if (data_out_.size()<cwnd_) {
+ dprintf("%s #%u sendctrl next in %llius (cwnd %.2f, data_out %i)\n",
+ tintstr(),id_,send_interval_,cwnd_,(int)data_out_.size());
return last_data_out_time_ + send_interval_;
} else {
- tint next_timeout = data_out_.front().time + ack_timeout();
- return last_data_out_time_ + next_timeout;
+ assert(data_out_.front().time!=TINT_NEVER);
+ return data_out_.front().time + ack_timeout();
}
}
-void Channel::BackOffOnLosses () {
+void Channel::BackOffOnLosses (float ratio) {
ack_rcvd_recent_ = 0;
ack_not_rcvd_recent_ = 0;
if (last_loss_time_<NOW-rtt_avg_) {
- cwnd_ /= 2;
+ cwnd_ *= ratio;
last_loss_time_ = NOW;
+ dprintf("%s #%u sendctrl backoff %3.2f\n",tintstr(),id_,cwnd_);
}
}
tint Channel::SlowStartNextSendTime () {
if (ack_not_rcvd_recent_) {
BackOffOnLosses();
- return SwitchSendControl(AIMD_CONTROL);
+ return SwitchSendControl(LEDBAT_CONTROL);//AIMD_CONTROL);
}
if (rtt_avg_/cwnd_<TINT_SEC/10)
- return SwitchSendControl(AIMD_CONTROL);
+ return SwitchSendControl(LEDBAT_CONTROL);//AIMD_CONTROL);
cwnd_+=ack_rcvd_recent_;
ack_rcvd_recent_=0;
return CwndRateNextSendTime();
tint Channel::AimdNextSendTime () {
if (ack_not_rcvd_recent_)
BackOffOnLosses();
- cwnd_ += ack_rcvd_recent_/cwnd_;
+ if (ack_rcvd_recent_) {
+ if (cwnd_>1)
+ cwnd_ += ack_rcvd_recent_/cwnd_;
+ else
+ cwnd_ *= 2;
+ }
ack_rcvd_recent_=0;
return CwndRateNextSendTime();
}
owd_cur = owd_current_[i];
}
if (ack_not_rcvd_recent_)
- BackOffOnLosses();
+ BackOffOnLosses(0.8);
ack_rcvd_recent_ = 0;
tint queueing_delay = owd_cur - owd_min;
tint off_target = LEDBAT_TARGET - queueing_delay;
cwnd_ += LEDBAT_GAIN * off_target / cwnd_;
+ if (cwnd_<1)
+ cwnd_ = 1;
+ if (owd_cur==TINT_NEVER || owd_min==TINT_NEVER)
+ cwnd_ = 1;
+ dprintf("%s #%u sendctrl ledbat %lli-%lli => %3.2f\n",
+ tintstr(),id_,owd_cur,owd_min,cwnd_);
return CwndRateNextSendTime();
}