00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #ifndef lint
00036 static const char rcsid[] =
00037 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/snoop.cc,v 1.25 2003/01/28 23:31:03 sfloyd Exp $ (UCB)";
00038 #endif
00039
00040 #include "snoop.h"
00041
00042 int hdr_snoop::offset_;
00043
00044 class SnoopHeaderClass : public PacketHeaderClass {
00045 public:
00046 SnoopHeaderClass() : PacketHeaderClass("PacketHeader/Snoop",
00047 sizeof(hdr_snoop)) {
00048 bind_offset(&hdr_snoop::offset_);
00049 }
00050 } class_snoophdr;
00051
00052 static class LLSnoopClass : public TclClass {
00053 public:
00054 LLSnoopClass() : TclClass("LL/LLSnoop") {}
00055 TclObject* create(int, const char*const*) {
00056 return (new LLSnoop());
00057 }
00058 } llsnoop_class;
00059
00060 static class SnoopClass : public TclClass {
00061 public:
00062 SnoopClass() : TclClass("Snoop") {}
00063 TclObject* create(int, const char*const*) {
00064 return (new Snoop());
00065 }
00066 } snoop_class;
00067
00068 Snoop::Snoop() : NsObject(),
00069 fstate_(0), lastSeen_(-1), lastAck_(-1),
00070 expNextAck_(0), expDupacks_(0), bufhead_(0),
00071 toutPending_(0), buftail_(0),
00072 wl_state_(SNOOP_WLEMPTY), wl_lastSeen_(-1), wl_lastAck_(-1),
00073 wl_bufhead_(0), wl_buftail_(0)
00074 {
00075 bind("snoopDisable_", &snoopDisable_);
00076 bind_time("srtt_", &srtt_);
00077 bind_time("rttvar_", &rttvar_);
00078 bind("maxbufs_", &maxbufs_);
00079 bind("snoopTick_", &snoopTick_);
00080 bind("g_", &g_);
00081 bind("tailTime_", &tailTime_);
00082 bind("rxmitStatus_", &rxmitStatus_);
00083 bind("lru_", &lru_);
00084
00085 rxmitHandler_ = new SnoopRxmitHandler(this);
00086
00087 int i;
00088 for (i = 0; i < SNOOP_MAXWIND; i++)
00089 pkts_[i] = 0;
00090 for (i = 0; i < SNOOP_WLSEQS; i++) {
00091 wlseqs_[i] = (hdr_seq *) malloc(sizeof(hdr_seq));
00092 wlseqs_[i]->seq = wlseqs_[i]->num = 0;
00093 }
00094 if (maxbufs_ == 0)
00095 maxbufs_ = SNOOP_MAXWIND;
00096 }
00097
00098 void
00099 Snoop::reset()
00100 {
00101
00102 fstate_ = 0;
00103 lastSeen_ = -1;
00104 lastAck_ = -1;
00105 expNextAck_ = 0;
00106 expDupacks_ = 0;
00107 bufhead_ = buftail_ = 0;
00108 if (toutPending_) {
00109 Scheduler::instance().cancel(toutPending_);
00110
00111 toutPending_ = 0;
00112 };
00113 for (int i = 0; i < SNOOP_MAXWIND; i++) {
00114 if (pkts_[i]) {
00115 Packet::free(pkts_[i]);
00116 pkts_[i] = 0;
00117 }
00118 }
00119 }
00120
00121 void
00122 Snoop::wlreset()
00123 {
00124 wl_state_ = SNOOP_WLEMPTY;
00125 wl_bufhead_ = wl_buftail_ = 0;
00126 for (int i = 0; i < SNOOP_WLSEQS; i++) {
00127 wlseqs_[i]->seq = wlseqs_[i]->num = 0;
00128 }
00129 }
00130
00131
00132 int
00133 Snoop::command(int argc, const char*const* argv)
00134 {
00135
00136
00137 if (argc == 3) {
00138 if (strcmp(argv[1], "llsnoop") == 0) {
00139 parent_ = (LLSnoop *) TclObject::lookup(argv[2]);
00140 if (parent_)
00141 recvtarget_ = parent_->uptarget();
00142 return (TCL_OK);
00143 }
00144
00145 if (strcmp(argv[1], "check-rxmit") == 0) {
00146 if (empty_()) {
00147 rxmitStatus_ = SNOOP_PROPAGATE;
00148 return (TCL_OK);
00149 }
00150
00151 Packet *p = pkts_[buftail_];
00152 hdr_snoop *sh = hdr_snoop::access(p);
00153
00154 if (sh->sndTime()!=-1 && sh->sndTime()<atoi(argv[2]) &&
00155 sh->numRxmit() == 0)
00156
00157 rxmitStatus_ = snoop_rxmit(p);
00158 else
00159 rxmitStatus_ = SNOOP_PROPAGATE;
00160 return (TCL_OK);
00161 }
00162 }
00163 return NsObject::command(argc, argv);
00164 }
00165
00166 void LLSnoop::recv(Packet *p, Handler *h)
00167 {
00168 Tcl &tcl = Tcl::instance();
00169 hdr_ip *iph = hdr_ip::access(p);
00170
00171
00172 hdr_cmn *ch = HDR_CMN(p);
00173 if(ch->direction() == hdr_cmn::UP)
00174
00175
00176 tcl.evalf("%s get-snoop %d %d", name(), iph->daddr(),
00177 iph->saddr());
00178
00179 else
00180 tcl.evalf("%s get-snoop %d %d", name(), iph->saddr(),
00181 iph->daddr());
00182
00183 Snoop *snoop = (Snoop *) TclObject::lookup(tcl.result());
00184
00185 snoop->recv(p, h);
00186
00187 if (integrate_)
00188 tcl.evalf("%s integrate %d %d", name(), iph->saddr(),
00189 iph->daddr());
00190 if (h)
00191 Scheduler::instance().schedule(h, &intr_, 0.000001);
00192 return;
00193 }
00194
00195
00196
00197
00198
00199 void
00200 Snoop::recv(Packet* p, Handler* h )
00201 {
00202
00203 hdr_cmn *ch = HDR_CMN(p);
00204 if(ch->direction() == hdr_cmn::UP) {
00205 handle((Event *) p);
00206 return;
00207 }
00208
00209 packet_t type = hdr_cmn::access(p)->ptype();
00210
00211
00212 if (type == PT_TCP)
00213 snoop_data(p);
00214
00215 else if (type == PT_ACK)
00216 snoop_wired_ack(p);
00217
00218 ch->direction() = hdr_cmn::DOWN;
00219 parent_->sendDown(p);
00220 }
00221
00222
00223
00224
00225
00226 void
00227 Snoop::handle(Event *e)
00228 {
00229
00230 Packet *p = (Packet *) e;
00231 packet_t type = hdr_cmn::access(p)->ptype();
00232
00233 int prop = SNOOP_PROPAGATE;
00234 Scheduler& s = Scheduler::instance();
00235
00236
00237 if (hdr_cmn::access(p)->error()) {
00238 parent_->drop(p);
00239 return;
00240 }
00241
00242 if (type == PT_ACK)
00243 prop = snoop_ack(p);
00244
00245 else if (type == PT_TCP)
00246 snoop_wless_data(p);
00247
00248 if (prop == SNOOP_PROPAGATE)
00249 s.schedule(recvtarget_, e, parent_->delay());
00250 else {
00251
00252 Packet::free(p);
00253 }
00254 }
00255
00256
00257
00258
00259
00260 void
00261 Snoop::snoop_data(Packet *p)
00262 {
00263 Scheduler &s = Scheduler::instance();
00264 int seq = hdr_tcp::access(p)->seqno();
00265 int resetPending = 0;
00266
00267
00268 if (fstate_ & SNOOP_ALIVE && seq == 0)
00269 reset();
00270 fstate_ |= SNOOP_ALIVE;
00271 if ((fstate_ & SNOOP_FULL) && !lru_) {
00272
00273 if (seq > lastSeen_)
00274 lastSeen_ = seq;
00275 return;
00276 }
00277
00278
00279
00280
00281
00282 if (parent_->ifq()->length() < parent_->ifq()->limit()-1)
00283 resetPending = snoop_insert(p);
00284 if (toutPending_ && resetPending == SNOOP_TAIL) {
00285 s.cancel(toutPending_);
00286
00287 toutPending_ = 0;
00288 }
00289 if (!toutPending_ && !empty_()) {
00290 toutPending_ = (Event *) (pkts_[buftail_]);
00291 s.schedule(rxmitHandler_, toutPending_, timeout());
00292 }
00293 return;
00294 }
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 int
00306 Snoop::snoop_insert(Packet *p)
00307 {
00308
00309
00310
00311 int i, seq = hdr_tcp::access(p)->seqno(), retval=0;
00312
00313 if (seq <= lastAck_)
00314 return retval;
00315
00316 if (fstate_ & SNOOP_FULL) {
00317
00318 printf("snoop full, making room\n");
00319 Packet::free(pkts_[buftail_]);
00320 pkts_[buftail_] = 0;
00321 buftail_ = next(buftail_);
00322 fstate_ |= ~SNOOP_FULL;
00323 }
00324
00325 if (seq > lastSeen_ || pkts_[buftail_] == 0) {
00326 i = bufhead_;
00327 bufhead_ = next(bufhead_);
00328 } else if (seq < hdr_snoop::access(pkts_[buftail_])->seqno()) {
00329 buftail_ = prev(buftail_);
00330 i = buftail_;
00331 } else {
00332 for (i = buftail_; i != bufhead_; i = next(i)) {
00333 hdr_snoop *sh = hdr_snoop::access(pkts_[i]);
00334 if (sh->seqno() == seq) {
00335
00336 sh->numRxmit() = 0;
00337 sh->senderRxmit() = 1;
00338 sh->sndTime() = Scheduler::instance().clock();
00339 return SNOOP_TAIL;
00340 } else if (sh->seqno() > seq) {
00341
00342
00343
00344
00345 Packet *temp = pkts_[prev(buftail_)];
00346 for (int j = buftail_; j != i; j = next(j))
00347 pkts_[prev(j)] = pkts_[j];
00348 i = prev(i);
00349 pkts_[i] = temp;
00350 buftail_ = prev(buftail_);
00351 break;
00352 }
00353 }
00354
00355
00356
00357 if (i == bufhead_)
00358 bufhead_ = next(bufhead_);
00359 }
00360
00361
00362 savepkt_(p, seq, i);
00363
00364 if (bufhead_ == buftail_)
00365 fstate_ |= SNOOP_FULL;
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376 if (seq < lastSeen_) {
00377 if (buftail_ == i) {
00378 hdr_snoop *sh = hdr_snoop::access(pkts_[i]);
00379 sh->senderRxmit() = 1;
00380 sh->numRxmit() = 0;
00381 }
00382 expNextAck_ = buftail_;
00383 retval = SNOOP_TAIL;
00384 } else
00385 lastSeen_ = seq;
00386
00387 return retval;
00388 }
00389
00390 void
00391 Snoop::savepkt_(Packet *p, int seq, int i)
00392 {
00393 pkts_[i] = p->copy();
00394 Packet *pkt = pkts_[i];
00395 hdr_snoop *sh = hdr_snoop::access(pkt);
00396 sh->seqno() = seq;
00397 sh->numRxmit() = 0;
00398 sh->senderRxmit() = 0;
00399 sh->sndTime() = Scheduler::instance().clock();
00400 }
00401
00402
00403
00404
00405
00406 int
00407 Snoop::snoop_ack(Packet *p)
00408 {
00409 Packet *pkt;
00410
00411 int ack = hdr_tcp::access(p)->seqno();
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 if (fstate_ & SNOOP_CLOSED || lastAck_ > ack)
00428 return SNOOP_PROPAGATE;
00429
00430 if (lastAck_ == ack) {
00431
00432
00433 pkt = pkts_[buftail_];
00434
00435 if (pkt == 0)
00436 return SNOOP_PROPAGATE;
00437
00438 hdr_snoop *sh = hdr_snoop::access(pkt);
00439
00440 if (pkt == 0 || sh->seqno() > ack + 1)
00441
00442 return SNOOP_PROPAGATE;
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452 if (expDupacks_ == 0) {
00453 #define RTX_THRESH 1
00454
00455 static int thresh = 0;
00456 if (thresh++ < RTX_THRESH)
00457
00458 return SNOOP_PROPAGATE;
00459
00460 thresh = 0;
00461
00462
00463 if (sh->senderRxmit())
00464 return SNOOP_PROPAGATE;
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 expDupacks_ = bufhead_ - expNextAck_;
00476 if (expDupacks_ < 0)
00477 expDupacks_ += SNOOP_MAXWIND;
00478 expDupacks_ -= RTX_THRESH + 1;
00479 expNextAck_ = next(buftail_);
00480
00481 if (sh->numRxmit() == 0)
00482 return snoop_rxmit(pkt);
00483 } else if (expDupacks_ > 0) {
00484 expDupacks_--;
00485 return SNOOP_SUPPRESS;
00486 } else if (expDupacks_ == -1) {
00487 if (sh->numRxmit() < 2) {
00488 return snoop_rxmit(pkt);
00489 }
00490 } else
00491 return SNOOP_PROPAGATE;
00492 } else {
00493
00494 fstate_ &= ~SNOOP_NOACK;
00495
00496
00497 double sndTime = snoop_cleanbufs_(ack);
00498
00499 if (sndTime != -1)
00500 snoop_rtt(sndTime);
00501
00502 expDupacks_ = 0;
00503 expNextAck_ = buftail_;
00504 lastAck_ = ack;
00505 }
00506 return SNOOP_PROPAGATE;
00507 }
00508
00509
00510
00511
00512
00513
00514
00515
00516 void
00517 Snoop::snoop_wless_data(Packet *p)
00518 {
00519 hdr_tcp *th = hdr_tcp::access(p);
00520 int i, seq = th->seqno();
00521
00522 if (wl_state_ & SNOOP_WLALIVE && seq == 0)
00523 wlreset();
00524 wl_state_ |= SNOOP_WLALIVE;
00525
00526 if (wl_state_ & SNOOP_WLEMPTY && seq >= wl_lastAck_) {
00527 wlseqs_[wl_bufhead_]->seq = seq;
00528 wlseqs_[wl_bufhead_]->num = 1;
00529 wl_buftail_ = wl_bufhead_;
00530 wl_bufhead_ = wl_next(wl_bufhead_);
00531 wl_lastSeen_ = seq;
00532 wl_state_ &= ~SNOOP_WLEMPTY;
00533 return;
00534 }
00535
00536 if (seq >= wl_lastSeen_) {
00537 wl_lastSeen_ = seq;
00538 i = wl_prev(wl_bufhead_);
00539 if (wlseqs_[i]->seq + wlseqs_[i]->num == seq) {
00540 wlseqs_[i]->num++;
00541 return;
00542 }
00543 i = wl_bufhead_;
00544 wl_bufhead_ = wl_next(wl_bufhead_);
00545 } else if (seq == wlseqs_[i = wl_buftail_]->seq - 1) {
00546 } else
00547 return;
00548
00549 wlseqs_[i]->seq = seq;
00550 wlseqs_[i]->num++;
00551
00552
00553 return;
00554 }
00555
00556
00557
00558
00559 void
00560 Snoop::snoop_wired_ack(Packet *p)
00561 {
00562 hdr_tcp *th = hdr_tcp::access(p);
00563 int ack = th->seqno();
00564 int i;
00565
00566 if (ack == wl_lastAck_ && snoop_wlessloss(ack)) {
00567 hdr_flags::access(p)->eln_ = 1;
00568 } else if (ack > wl_lastAck_) {
00569
00570 for (i = wl_buftail_; i != wl_bufhead_; i = wl_next(i)) {
00571 hdr_seq *t = wlseqs_[i];
00572 if (t->seq + t->num - 1 <= ack) {
00573 t->seq = t->num = 0;
00574 } else if (ack < t->seq) {
00575 break;
00576 } else if (ack < t->seq + t->num - 1) {
00577
00578 t->num -= ack - t->seq +1;
00579 t->seq = ack + 1;
00580 break;
00581 }
00582 }
00583 wl_buftail_ = i;
00584 if (wl_buftail_ == wl_bufhead_)
00585 wl_state_ |= SNOOP_WLEMPTY;
00586 wl_lastAck_ = ack;
00587
00588 if (wl_bufhead_ != wl_buftail_ && snoop_wlessloss(ack))
00589 hdr_flags::access(p)->eln_ = 1;
00590 }
00591 }
00592
00593
00594
00595
00596
00597
00598
00599 int
00600 Snoop::snoop_wlessloss(int ack)
00601 {
00602 if ((wl_bufhead_ == wl_buftail_) || wlseqs_[wl_buftail_]->seq > ack+1)
00603 return 1;
00604 return 0;
00605 }
00606
00607
00608
00609
00610 double
00611 Snoop::snoop_cleanbufs_(int ack)
00612 {
00613 Scheduler &s = Scheduler::instance();
00614 double sndTime = -1;
00615
00616 if (toutPending_) {
00617 s.cancel(toutPending_);
00618
00619 toutPending_ = 0;
00620 };
00621
00622 if (empty_())
00623 return sndTime;
00624
00625 int i = buftail_;
00626 do {
00627 hdr_snoop *sh = hdr_snoop::access(pkts_[i]);
00628 int seq = hdr_tcp::access(pkts_[i])->seqno();
00629
00630 if (seq <= ack) {
00631 sndTime = sh->sndTime();
00632 Packet::free(pkts_[i]);
00633 pkts_[i] = 0;
00634 fstate_ &= ~SNOOP_FULL;
00635 } else if (seq > ack)
00636 break;
00637 i = next(i);
00638 } while (i != bufhead_);
00639
00640 if ((i != buftail_) || (bufhead_ != buftail_)) {
00641 fstate_ &= ~SNOOP_FULL;
00642 buftail_ = i;
00643 }
00644 if (!empty_()) {
00645 toutPending_ = (Event *) (pkts_[buftail_]);
00646 s.schedule(rxmitHandler_, toutPending_, timeout());
00647 hdr_snoop *sh = hdr_snoop::access(pkts_[buftail_]);
00648 tailTime_ = sh->sndTime();
00649 }
00650
00651 return sndTime;
00652 }
00653
00654
00655
00656
00657 void
00658 Snoop::snoop_rtt(double sndTime)
00659 {
00660 double rtt = Scheduler::instance().clock() - sndTime;
00661
00662 if (parent_->integrate()) {
00663 parent_->snoop_rtt(sndTime);
00664 return;
00665 }
00666
00667 if (rtt > 0) {
00668 srtt_ = g_*srtt_ + (1-g_)*rtt;
00669 double delta = rtt - srtt_;
00670 if (delta < 0)
00671 delta = -delta;
00672 if (rttvar_ != 0)
00673 rttvar_ = g_*delta + (1-g_)*rttvar_;
00674 else
00675 rttvar_ = delta;
00676 }
00677 }
00678
00679
00680
00681
00682
00683 void
00684 LLSnoop::snoop_rtt(double sndTime)
00685 {
00686 double rtt = Scheduler::instance().clock() - sndTime;
00687 if (rtt > 0) {
00688 srtt_ = g_*srtt_ + (1-g_)*rtt;
00689 double delta = rtt - srtt_;
00690 if (delta < 0)
00691 delta = -delta;
00692 if (rttvar_ != 0)
00693 rttvar_ = g_*delta + (1-g_)*rttvar_;
00694 else
00695 rttvar_ = delta;
00696 }
00697 }
00698
00699
00700
00701
00702 int
00703 Snoop::snoop_qlong()
00704 {
00705
00706
00707
00708 return 1;
00709
00710 }
00711
00712
00713
00714
00715 int
00716 Snoop::snoop_rxmit(Packet *pkt)
00717 {
00718 Scheduler& s = Scheduler::instance();
00719 if (pkt != 0) {
00720 hdr_snoop *sh = hdr_snoop::access(pkt);
00721 if (sh->numRxmit() < SNOOP_MAX_RXMIT && snoop_qlong()) {
00722
00723
00724 #if 0
00725 printf("%f Rxmitting packet %d\n", s.clock(),
00726 hdr_tcp::access(pkt)->seqno());
00727 #endif
00728
00729
00730 hdr_cmn *ch = HDR_CMN(pkt);
00731 ch->direction() = hdr_cmn::DOWN;
00732
00733 sh->sndTime() = s.clock();
00734 sh->numRxmit() = sh->numRxmit() + 1;
00735 Packet *p = pkt->copy();
00736 parent_->sendDown(p);
00737 } else
00738 return SNOOP_PROPAGATE;
00739 }
00740
00741 if (toutPending_) {
00742 s.cancel(toutPending_);
00743
00744 };
00745 toutPending_ = (Event *)pkt;
00746 s.schedule(rxmitHandler_, toutPending_, timeout());
00747 return SNOOP_SUPPRESS;
00748 }
00749
00750 void
00751 Snoop::snoop_cleanup()
00752 {
00753 }
00754
00755 void
00756 SnoopRxmitHandler::handle(Event *)
00757 {
00758 Packet *p = snoop_->pkts_[snoop_->buftail_];
00759 snoop_->toutPending_ = 0;
00760 if (p == 0)
00761 return;
00762 hdr_snoop *sh = hdr_snoop::access(p);
00763 if (sh->seqno() != snoop_->lastAck_ + 1)
00764 return;
00765 if ((snoop_->bufhead_ != snoop_->buftail_) ||
00766 (snoop_->fstate_ & SNOOP_FULL)) {
00767
00768 if (snoop_->snoop_rxmit(p) == SNOOP_SUPPRESS)
00769 snoop_->expNextAck_ = snoop_->next(snoop_->buftail_);
00770 }
00771 }
00772
00773
00774