📄 tcp-sink.cc
字号:
bind_time("interval_", &interval_);
}
void DelAckSink::recv(Packet* pkt, Handler*)
{
int numToDeliver;
int numBytes = hdr_cmn::access(pkt)->size();
hdr_tcp *th = hdr_tcp::access(pkt);
acker_->update_ts(th->seqno(),th->ts());
numToDeliver = acker_->update(th->seqno(), numBytes);
if (numToDeliver)
recvBytes(numToDeliver);
// If there's no timer and the packet is in sequence, set a timer.
// Otherwise, send the ack and update the timer.
if (delay_timer_.status() != TIMER_PENDING &&
th->seqno() == acker_->Seqno()) {
// There's no timer, so we can set one and choose
// to delay this ack.
// If we're following RFC2581 (section 4.2) exactly,
// we should only delay the ACK if we're know we're
// not doing recovery, i.e. not gap-filling.
// Since this is a change to previous ns behaviour,
// it's controlled by an optional bound flag.
// discussed April 2000 in the ns-users list archives.
if (RFC2581_immediate_ack_ &&
(th->seqno() < acker_->Maxseen())) {
// don't delay the ACK since
// we're filling in a gap
} else {
// delay the ACK and start the timer.
save_ = pkt;
delay_timer_.resched(interval_);
return;
}
}
// If there was a timer, turn it off.
if (delay_timer_.status() == TIMER_PENDING)
delay_timer_.cancel();
ack(pkt);
if (save_ != NULL) {
Packet::free(save_);
save_ = NULL;
}
Packet::free(pkt);
}
void DelAckSink::timeout(int)
{
// The timer expired so we ACK the last packet seen.
Packet* pkt = save_;
ack(pkt);
save_ = NULL;
Packet::free(pkt);
}
void DelayTimer::expire(Event* /*e*/) {
a_->timeout(0);
}
/* "sack1-tcp-sink" is for Matt and Jamshid's implementation of sack. */
class SackStack {
protected:
int size_;
int cnt_;
struct Sf_Entry {
int left_;
int right_;
} *SFE_;
public:
SackStack(int); // create a SackStack of size (int)
~SackStack();
int& head_right(int n = 0) { return SFE_[n].right_; }
int& head_left(int n = 0) { return SFE_[n].left_; }
int cnt() { return cnt_; } // how big is the stack
void reset() {
register int i;
for (i = 0; i < cnt_; i++)
SFE_[i].left_ = SFE_[i].right_ = -1;
cnt_ = 0;
}
inline void push(int n = 0) {
if (cnt_ >= size_) cnt_ = size_ - 1; // overflow check
register int i;
for (i = cnt_-1; i >= n; i--)
SFE_[i+1] = SFE_[i]; // not efficient for big size
cnt_++;
}
inline void pop(int n = 0) {
register int i;
for (i = n; i < cnt_-1; i++)
SFE_[i] = SFE_[i+1]; // not efficient for big size
SFE_[i].left_ = SFE_[i].right_ = -1;
cnt_--;
}
};
SackStack::SackStack(int sz)
{
register int i;
size_ = sz;
SFE_ = new Sf_Entry[sz];
for (i = 0; i < sz; i++)
SFE_[i].left_ = SFE_[i].right_ = -1;
cnt_ = 0;
}
SackStack::~SackStack()
{
delete SFE_;
}
static class Sack1TcpSinkClass : public TclClass {
public:
Sack1TcpSinkClass() : TclClass("Agent/TCPSink/Sack1") {}
TclObject* create(int, const char*const*) {
Sacker* sacker = new Sacker;
TcpSink* sink = new TcpSink(sacker);
sacker->configure(sink);
return (sink);
}
} class_sack1tcpsink;
static class Sack1DelAckTcpSinkClass : public TclClass {
public:
Sack1DelAckTcpSinkClass() : TclClass("Agent/TCPSink/Sack1/DelAck") {}
TclObject* create(int, const char*const*) {
Sacker* sacker = new Sacker;
TcpSink* sink = new DelAckSink(sacker);
sacker->configure(sink);
return (sink);
}
} class_sack1delacktcpsink;
void Sacker::configure(TcpSink *sink)
{
if (sink == NULL) {
fprintf(stderr, "warning: Sacker::configure(): no TCP sink!\n");
return;
}
TracedInt& nblocks = sink->max_sack_blocks_;
if (int(nblocks) > NSA) {
fprintf(stderr, "warning(Sacker::configure): TCP header limits number of SACK blocks to %d, not %d\n", NSA, int(nblocks));
nblocks = NSA;
}
sf_ = new SackStack(int(nblocks));
nblocks.tracer(this);
base_nblocks_ = int(nblocks);
dsacks_ = &(sink->generate_dsacks_);
}
void
Sacker::trace(TracedVar *v)
{
// we come here if "nblocks" changed
TracedInt* ti = (TracedInt*) v;
if (int(*ti) > NSA) {
fprintf(stderr, "warning(Sacker::trace): TCP header limits number of SACK blocks to %d, not %d\n", NSA, int(*ti));
*ti = NSA;
}
int newval = int(*ti);
delete sf_;
sf_ = new SackStack(newval);
base_nblocks_ = newval;
}
void Sacker::reset()
{
sf_->reset();
Acker::reset();
}
Sacker::~Sacker()
{
delete sf_;
}
void Sacker::append_ack(hdr_cmn* ch, hdr_tcp* h, int old_seqno) const
{
// ch and h are the common and tcp headers of the Ack being constructed
// old_seqno is the sequence # of the packet we just got
int sack_index, i, sack_right, sack_left;
int recent_sack_left, recent_sack_right;
int seqno = Seqno();
// the last in-order packet seen (i.e. the cumulative ACK # - 1)
sack_index = 0;
sack_left = sack_right = -1;
// initialization; sack_index=0 and sack_{left,right}= -1
if (old_seqno < 0) {
printf("Error: invalid packet number %d\n", old_seqno);
} else if (seqno >= maxseen_ && (sf_->cnt() != 0))
sf_->reset();
// if the Cumulative ACK seqno is at or beyond the right edge
// of the window, and if the SackStack is not empty, reset it
// (empty it)
else if (( (seqno < maxseen_) || is_dup_ ) && (base_nblocks_ > 0)) {
// Otherwise, if the received packet is to the left of
// the right edge of the receive window (but not at
// the right edge), OR if it is a duplicate, AND we
// can have 1 or more Sack blocks, then execute the
// following, which computes the most recent Sack
// block
if ((*dsacks_) && is_dup_) {
// Record the DSACK Block
h->sa_left(sack_index) = old_seqno;
h->sa_right(sack_index) = old_seqno+1;
// record the block
sack_index++;
#ifdef DEBUGDSACK
printf("%f\t Generating D-SACK for packet %d\n", Scheduler::instance().clock(),old_seqno);
#endif
}
// Build FIRST (traditional) SACK block
// If we already had a DSACK block due to a duplicate
// packet, and if that duplicate packet is in the
// receiver's window (i.e. the packet's sequence
// number is > than the cumulative ACK) then the
// following should find the SACK block it's a subset
// of. If it's <= cum ACK field then the following
// shouldn't record a superset SACK block for it.
if (sack_index >= base_nblocks_) {
printf("Error: can't use DSACK with less than 2 SACK blocks\n");
} else {
sack_right=-1;
// look rightward for first hole
// start at the current packet
for (i=old_seqno; i<=maxseen_; i++) {
if (!seen_[i & MWM]) {
sack_right=i;
break;
}
}
// if there's no hole set the right edge of the sack
// to be the next expected packet
if (sack_right == -1) {
sack_right = maxseen_+1;
}
// if the current packet's seqno is smaller than the
// left edge of the window, set the sack_left to 0
if (old_seqno <= seqno) {
sack_left = 0;
// don't record/send the block
} else {
// look leftward from right edge for first hole
for (i = sack_right-1; i > seqno; i--) {
if (!seen_[i & MWM]) {
sack_left = i+1;
break;
}
}
h->sa_left(sack_index) = sack_left;
h->sa_right(sack_index) = sack_right;
// record the block
sack_index++;
}
recent_sack_left = sack_left;
recent_sack_right = sack_right;
// first sack block is built, check the others
// make sure that if max_sack_blocks has been made
// large from tcl we don't over-run the stuff we
// allocated in Sacker::Sacker()
int k = 0;
while (sack_index < base_nblocks_) {
sack_left = sf_->head_left(k);
sack_right = sf_->head_right(k);
// no more history
if (sack_left < 0 || sack_right < 0 ||
sack_right > maxseen_ + 1)
break;
// newest ack "covers up" this one
if (recent_sack_left <= sack_left &&
recent_sack_right >= sack_right) {
sf_->pop(k);
continue;
}
h->sa_left(sack_index) = sack_left;
h->sa_right(sack_index) = sack_right;
// store the old sack (i.e. move it down one)
sack_index++;
k++;
}
if (old_seqno > seqno) {
/* put most recent block onto stack */
sf_->push();
// this just moves things down 1 from the
// beginning, but it doesn't push any values
// on the stack
sf_->head_left() = recent_sack_left;
sf_->head_right() = recent_sack_right;
// this part stores the left/right values at
// the top of the stack (slot 0)
}
} // this '}' is for the DSACK base_nblocks_ >= test;
// (didn't feel like re-indenting all the code and
// causing a large diff)
}
h->sa_length() = sack_index;
// set the Length of the sack stack in the header
ch->size() += sack_index * 8;
// change the size of the common header to account for the
// Sack strings (2 4-byte words for each element)
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -