📄 snoop.cc
字号:
voidSnoop::savepkt_(Packet *p, int seq, int i){ pkts_[i] = p->copy(); Packet *pkt = pkts_[i]; hdr_snoop *sh = hdr_snoop::access(pkt); sh->seqno() = seq; sh->numRxmit() = 0; sh->senderRxmit() = 0; sh->sndTime() = Scheduler::instance().clock();}/* * Ack processing in snoop protocol. We know for sure that this is an ack. * Return SNOOP_SUPPRESS if ack is to be suppressed and SNOOP_PROPAGATE o.w. */intSnoop::snoop_ack(Packet *p){ Packet *pkt; int ack = hdr_tcp::access(p)->seqno(); /* * There are 3 cases: * 1. lastAck_ > ack. In this case what has happened is * that the acks have come out of order, so we don't * do any local processing but forward it on. * 2. lastAck_ == ack. This is a duplicate ack. If we have * the packet we resend it, and drop the dupack. * Otherwise we never got it from the fixed host, so we * need to let the dupack get through. * Set expDupacks_ to number of packets already sent * This is the number of dup acks to ignore. * 3. lastAck_ < ack. Set lastAck_ = ack, and update * the head of the buffer queue. Also clean up ack'd packets. */ if (fstate_ & SNOOP_CLOSED || lastAck_ > ack) return SNOOP_PROPAGATE; // send ack onward if (lastAck_ == ack) { /* A duplicate ack; pure window updates don't occur in ns. */ pkt = pkts_[buftail_]; if (pkt == 0) return SNOOP_PROPAGATE; hdr_snoop *sh = hdr_snoop::access(pkt); if (pkt == 0 || sh->seqno() > ack + 1) /* don't have packet, letting thru' */ return SNOOP_PROPAGATE; /* * We have the packet: one of 3 possibilities: * 1. We are not expecting any dupacks (expDupacks_ == 0) * 2. We are expecting dupacks (expDupacks_ > 0) * 3. We are in an inconsistent state (expDupacks_ == -1) */ if (expDupacks_ == 0) { // not expecting it#define RTX_THRESH 1 static int thresh = 0; if (thresh++ < RTX_THRESH) /* no action if under RTX_THRESH */ return SNOOP_PROPAGATE; thresh = 0; // if the packet is a sender retransmission, pass on if (sh->senderRxmit()) return SNOOP_PROPAGATE; /* * Otherwise, not triggered by sender. If this is * the first dupack recd., we must determine how many * dupacks will arrive that must be ignored, and also * rexmit the desired packet. Note that expDupacks_ * will be -1 if we miscount for some reason. */ expDupacks_ = bufhead_ - expNextAck_; if (expDupacks_ < 0) expDupacks_ += SNOOP_MAXWIND; expDupacks_ -= RTX_THRESH + 1; expNextAck_ = next(buftail_); if (sh->numRxmit() == 0) return snoop_rxmit(pkt); } else if (expDupacks_ > 0) { expDupacks_--; return SNOOP_SUPPRESS; } else if (expDupacks_ == -1) { if (sh->numRxmit() < 2) { return snoop_rxmit(pkt); } } else // let sender deal with it return SNOOP_PROPAGATE; } else { // a new ack fstate_ &= ~SNOOP_NOACK; // have seen at least 1 new ack /* free buffers */ double sndTime = snoop_cleanbufs_(ack); if (sndTime != -1) snoop_rtt(sndTime); expDupacks_ = 0; expNextAck_ = buftail_; lastAck_ = ack; } return SNOOP_PROPAGATE;}/* * Handle data packets that arrive from a wireless link, and we're not * the end recipient. See if there are any holes in the transmission, and * if there are, mark them as candidates for wireless loss. Then, when * (dup)acks troop back for this loss, set the ELN bit in their header, to * help the sender (or a snoop agent downstream) retransmit. */voidSnoop::snoop_wless_data(Packet *p){ hdr_tcp *th = hdr_tcp::access(p); int i, seq = th->seqno(); if (wl_state_ & SNOOP_WLALIVE && seq == 0) wlreset(); wl_state_ |= SNOOP_WLALIVE; if (wl_state_ & SNOOP_WLEMPTY && seq >= wl_lastAck_) { wlseqs_[wl_bufhead_]->seq = seq; wlseqs_[wl_bufhead_]->num = 1; wl_buftail_ = wl_bufhead_; wl_bufhead_ = wl_next(wl_bufhead_); wl_lastSeen_ = seq; wl_state_ &= ~SNOOP_WLEMPTY; return; } /* WL data list definitely not empty at this point. */ if (seq >= wl_lastSeen_) { wl_lastSeen_ = seq; i = wl_prev(wl_bufhead_); if (wlseqs_[i]->seq + wlseqs_[i]->num == seq) { wlseqs_[i]->num++; return; } i = wl_bufhead_; wl_bufhead_ = wl_next(wl_bufhead_); } else if (seq == wlseqs_[i = wl_buftail_]->seq - 1) { } else return; wlseqs_[i]->seq = seq; wlseqs_[i]->num++; /* Ignore network out-of-ordering and retransmissions for now */ return;}/* * Ack from wired side (for sender on "other" side of wireless link. */void Snoop::snoop_wired_ack(Packet *p){ hdr_tcp *th = hdr_tcp::access(p); int ack = th->seqno(); int i; if (ack == wl_lastAck_ && snoop_wlessloss(ack)) { hdr_flags::access(p)->eln_ = 1; } else if (ack > wl_lastAck_) { /* update info about unack'd data */ for (i = wl_buftail_; i != wl_bufhead_; i = wl_next(i)) { hdr_seq *t = wlseqs_[i]; if (t->seq + t->num - 1 <= ack) { t->seq = t->num = 0; } else if (ack < t->seq) { break; } else if (ack < t->seq + t->num - 1) { /* ack for part of a block */ t->num -= ack - t->seq +1; t->seq = ack + 1; break; } } wl_buftail_ = i; if (wl_buftail_ == wl_bufhead_) wl_state_ |= SNOOP_WLEMPTY; wl_lastAck_ = ack; /* Even a new ack could cause an ELN to be set. */ if (wl_bufhead_ != wl_buftail_ && snoop_wlessloss(ack)) hdr_flags::access(p)->eln_ = 1; }}/* * Return 1 if we think this packet loss was not congestion-related, and * 0 otherwise. This function simply implements the lookup into the table * that maintains this info; most of the hard work is done in * snoop_wless_data() and snoop_wired_ack(). */intSnoop::snoop_wlessloss(int ack){ if ((wl_bufhead_ == wl_buftail_) || wlseqs_[wl_buftail_]->seq > ack+1) return 1; return 0;}/* * clean snoop cache of packets that have been acked. */doubleSnoop::snoop_cleanbufs_(int ack){ Scheduler &s = Scheduler::instance(); double sndTime = -1; if (toutPending_) { s.cancel(toutPending_); // xxx: I think that toutPending_ doesn't need to be freed because snoop didn't allocate it (but I'm not sure). toutPending_ = 0; }; if (empty_()) return sndTime; int i = buftail_; do { hdr_snoop *sh = hdr_snoop::access(pkts_[i]); int seq = hdr_tcp::access(pkts_[i])->seqno(); if (seq <= ack) { sndTime = sh->sndTime(); Packet::free(pkts_[i]); pkts_[i] = 0; fstate_ &= ~SNOOP_FULL; /* XXX redundant? */ } else if (seq > ack) break; i = next(i); } while (i != bufhead_); if ((i != buftail_) || (bufhead_ != buftail_)) { fstate_ &= ~SNOOP_FULL; buftail_ = i; } if (!empty_()) { toutPending_ = (Event *) (pkts_[buftail_]); s.schedule(rxmitHandler_, toutPending_, timeout()); hdr_snoop *sh = hdr_snoop::access(pkts_[buftail_]); tailTime_ = sh->sndTime(); } return sndTime;}/* * Calculate smoothed rtt estimate and linear deviation. */voidSnoop::snoop_rtt(double sndTime){ double rtt = Scheduler::instance().clock() - sndTime; if (parent_->integrate()) { parent_->snoop_rtt(sndTime); return; } if (rtt > 0) { srtt_ = g_*srtt_ + (1-g_)*rtt; double delta = rtt - srtt_; if (delta < 0) delta = -delta; if (rttvar_ != 0) rttvar_ = g_*delta + (1-g_)*rttvar_; else rttvar_ = delta; }}/* * Calculate smoothed rtt estimate and linear deviation. */voidLLSnoop::snoop_rtt(double sndTime){ double rtt = Scheduler::instance().clock() - sndTime; if (rtt > 0) { srtt_ = g_*srtt_ + (1-g_)*rtt; double delta = rtt - srtt_; if (delta < 0) delta = -delta; if (rttvar_ != 0) rttvar_ = g_*delta + (1-g_)*rttvar_; else rttvar_ = delta; }}/* * Returns 1 if recent queue length is <= half the maximum and 0 otherwise. */int Snoop::snoop_qlong(){ /* For now only instantaneous lengths */ // if (parent_->ifq()->length() <= 3*parent_->ifq()->limit()/4) return 1; // return 0;}/* * Ideally, would like to schedule snoop retransmissions at higher priority. */intSnoop::snoop_rxmit(Packet *pkt){ Scheduler& s = Scheduler::instance(); if (pkt != 0) { hdr_snoop *sh = hdr_snoop::access(pkt); if (sh->numRxmit() < SNOOP_MAX_RXMIT && snoop_qlong()) { /* && sh->seqno() == lastAck_+1) */ #if 0 printf("%f Rxmitting packet %d\n", s.clock(), hdr_tcp::access(pkt)->seqno());#endif // need to specify direction, in this case, down hdr_cmn *ch = HDR_CMN(pkt); ch->direction() = hdr_cmn::DOWN; // Ben added sh->sndTime() = s.clock(); sh->numRxmit() = sh->numRxmit() + 1; Packet *p = pkt->copy(); parent_->sendDown(p); } else return SNOOP_PROPAGATE; } /* Reset timeout for later time. */ if (toutPending_) { s.cancel(toutPending_); // xxx: I think that toutPending_ doesn't need to be freed because snoop didn't allocate it (but I'm not sure). }; toutPending_ = (Event *)pkt; s.schedule(rxmitHandler_, toutPending_, timeout()); return SNOOP_SUPPRESS;}void Snoop::snoop_cleanup(){}voidSnoopRxmitHandler::handle(Event *){ Packet *p = snoop_->pkts_[snoop_->buftail_]; snoop_->toutPending_ = 0; if (p == 0) return; hdr_snoop *sh = hdr_snoop::access(p); if (sh->seqno() != snoop_->lastAck_ + 1) return; if ((snoop_->bufhead_ != snoop_->buftail_) || (snoop_->fstate_ & SNOOP_FULL)) { // printf("%f Snoop timeout\n", Scheduler::instance().clock()); if (snoop_->snoop_rxmit(p) == SNOOP_SUPPRESS) snoop_->expNextAck_ = snoop_->next(snoop_->buftail_); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -