dest_queue.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 1997 Regents of the University of California.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *      This product includes software developed by the Computer Systems
00017  *      Engineering Group at Lawrence Berkeley Laboratory.
00018  * 4. Neither the name of the University nor of the Laboratory may be used
00019  *    to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  */
00034 /* Ported from CMU/Monarch's code*/
00035 
00036 /* 
00037    dest_queue.cc
00038    $Id: dest_queue.cc,v 1.2 1999/08/12 21:17:11 yaxu Exp $
00039    
00040    implement a group of resequencing queues.  one for each source of packets.
00041    the name destination queue is a misnomer.
00042    */
00043 
00044 #include <imep/dest_queue.h>
00045 #ifdef TEST_ONLY
00046 #include <stdio.h>
00047 #else
00048 #include <imep/imep.h>
00049 #endif
00050 #ifndef TEST_ONLY
00051 #define CURRENT_TIME Scheduler::instance().clock()
00052 #else
00053 extern double CURRENT_TIME;
00054 #endif
00055 
00056 
00057 static const int verbose = 0;
00058 
00060 // Transmission Queue Entry
00061 txent::txent(double e, u_int32_t s, Packet *p)
00062 {
00063     expire_ = e;
00064     seqno_ = s;
00065     pkt_ = p;
00066 }
00067 
00069 // Destination Queue Entry
00070 dstent::dstent(nsaddr_t index)
00071 {
00072     LIST_INIT(&txentHead);
00073     ipaddr_ = index;
00074     seqno_ = ILLEGAL_SEQ;
00075 }
00076 
00077 static int
00078 SEQ_GT(u_int8_t a, u_int8_t b)
00079 {
00080   int8_t reg = (int8_t)a - (int8_t) b;
00081   return reg > 0;
00082 }
00083     
00084 void
00085 dstent::addEntry(double e, u_int32_t s, Packet *p)
00086 {
00087     txent *t, *u, *v = 0;
00088 
00089     if((t = findEntry(s)) == 0) {
00090         t = new txent(e, s, p);
00091         assert(t);
00092 
00093         for(u = txentHead.lh_first; u; u = u->link.le_next) {
00094             if(SEQ_GT(u->seqno(), s))
00095               break;
00096             v = u;
00097         }
00098 
00099         if(u == 0 && v == 0) {
00100             LIST_INSERT_HEAD(&txentHead, t, link);
00101         } else if(u) {
00102             LIST_INSERT_BEFORE(u, t, link);
00103         } else {
00104             assert(v);
00105             LIST_INSERT_AFTER(v, t, link);
00106         }
00107 
00108     } else {
00109         Packet::free(p);
00110         // already have a copy of this packet
00111     }
00112 
00113 #ifdef  DEBUG
00114     // verify that I did not fuck up...
00115     u_int32_t max = 0;
00116     for(t = txentHead.lh_first; t; t = t->link.le_next) {
00117         if(max == 0)
00118             max = t->seqno();
00119         else {
00120             assert(t->seqno() > max);
00121             max = t->seqno();
00122         }
00123     } 
00124 #endif
00125 }            
00126 
00127 void
00128 dstent::delEntry(txent *t)
00129 {
00130     LIST_REMOVE(t, link);
00131     delete t;
00132 }
00133 
00134 txent*
00135 dstent::findEntry(u_int32_t s)
00136 {
00137     txent *t;
00138 
00139     for(t = txentHead.lh_first; t; t = t->link.le_next) {
00140         if(t->seqno() == s)
00141             return t;
00142     }
00143     return 0;
00144 }
00145 
00146 txent*
00147 dstent::findFirstEntry(void)
00148 {
00149     return txentHead.lh_first;
00150     // this gives the minimum sequence number for the destination
00151 }
00152 
00154 // Destination Queue
00155 dstQueue::dstQueue(imepAgent *a, nsaddr_t index) : agent_(a), ipaddr_(index)
00156 {
00157     LIST_INIT(&dstentHead);
00158 }
00159 
00160 void
00161 dstQueue::addEntry(nsaddr_t dst, double e, u_int32_t s, Packet *p)
00162 {
00163     dstent *t;
00164 
00165     if((t = findEntry(dst)) == 0) {
00166         t = new dstent(dst);
00167         assert(t);
00168         LIST_INSERT_HEAD(&dstentHead, t, link);
00169     }
00170 
00171     if (NULL == t->txentHead.lh_first) agent_->stats.num_holes_created++;
00172     t->addEntry(e, s, p);
00173 }
00174 
00175     
00176 dstent*
00177 dstQueue::findEntry(nsaddr_t dst)
00178 {
00179     dstent *t;
00180 
00181     for(t = dstentHead.lh_first; t; t = t->link.le_next) {
00182         if(t->ipaddr() == dst)
00183             return t;
00184     }
00185     return 0;
00186 }
00187 
00190 
00191 Packet*
00192 dstQueue::getPacket(nsaddr_t dst, u_int32_t seqno)
00193 {
00194     dstent *d;
00195     txent *t;
00196 
00197     for(d = dstentHead.lh_first; d; d = d->link.le_next) {
00198         if(d->ipaddr() == dst)
00199             break;
00200     }
00201 
00202     if(d && (t = d->findEntry(seqno))) {
00203         Packet *p = t->pkt();
00204         d->delEntry(t);
00205 
00206         // make sure packets come out in increasing order only
00207         //  int8_t reg = (int8_t) seqno - (int8_t) d->seqno();
00208         //assert(reg > 0); // SEQ_GT(seqno, d->seqno())
00209         //d->seqno() = seqno; 
00210 
00211         return p;
00212     }
00213     return 0;
00214 }
00215 
00216 double
00217 dstQueue::getNextExpire()
00218 {
00219     dstent *t;
00220     Time min = 0.0;
00221 
00222     for(t = dstentHead.lh_first; t; t = t->link.le_next) {
00223         Time texp = t->expire(); // computed by traversing a list
00224         if(min == 0.0 || (texp && texp < min))
00225             min = texp;
00226     }
00227     if (verbose)
00228       agent_->trace("T %.9f _%d_ dest_queue -  getNextExpire is %.9f",
00229             CURRENT_TIME, ipaddr_, min);
00230 
00231     return min;
00232 }
00233 
00234 Packet*
00235 dstQueue::getNextPacket(u_int32_t& s)
00236 {
00237     dstent *d;
00238 
00239     for(d = dstentHead.lh_first; d; d = d->link.le_next) {
00240       txent *t = d->findFirstEntry();
00241 
00242       if (t == 0) 
00243         {
00244           d->seqno() = ILLEGAL_SEQ;
00245           continue; // no packets here
00246         }
00247 
00248       Time texp = d->expire();
00249       assert(texp);
00250 #ifdef TEST_ONLY
00251       fprintf(stderr,
00252           "IN:\td->expire: %f, d->seqno: %d, t->expire: %f, t->seqno: %d\n",
00253           d->expire(), d->seqno(), t->expire(), t->seqno());
00254 #endif
00255       if (texp > CURRENT_TIME && d->seqno() == ILLEGAL_SEQ) continue;
00256 
00257       if (t->expire() <= CURRENT_TIME)
00258         { // remember this seq as starting a chain we can pull off
00259           d->seqno() = t->seqno();
00260         }
00261       else if (d->seqno() != ILLEGAL_SEQ && t->seqno() != (u_int8_t) (d->seqno() + 1))
00262         { // the next pkt isn't part of the chain we were pulling off
00263           // stop pulling off packets
00264           d->seqno() = ILLEGAL_SEQ;
00265           continue;     
00266         }
00267 
00268         Packet *p = t->pkt();
00269         assert(p);
00270 
00271         s = t->seqno();
00272 
00273 #ifdef TEST_ONLY
00274         fprintf(stderr, "\t%s: returning seqno: %d\n",
00275             __FUNCTION__, s);
00276 #endif
00277         if (d->seqno() != ILLEGAL_SEQ) 
00278           { // advance d->seqno() along the chain
00279         d->seqno() = t->seqno();
00280           }
00281         
00282         d->delEntry(t);
00283 #ifdef TEST_ONLY
00284       fprintf(stderr,
00285           "OUT:\td->expire: %f, d->seqno: %d, t->expire: %f, t->seqno: %d\n",
00286           d->expire(), d->seqno(), t->expire(), t->seqno());
00287 #endif
00288         return p;
00289     }
00290     return 0;
00291 }
00292 
00293 void 
00294 dstQueue::deleteDst(nsaddr_t dst)
00295 {
00296   dstent *d;
00297   txent *t;
00298   
00299   if (verbose)
00300     agent_->trace("T %.9f _%d_ purge dstQ id %d",
00301           CURRENT_TIME, ipaddr_, dst);
00302 
00303   for(d = dstentHead.lh_first; d; d = d->link.le_next) 
00304     {
00305       if(d->ipaddr() == dst)
00306     break;
00307     }
00308   if (!d) return;
00309 
00310   while ((t = d->findFirstEntry()))
00311     {
00312       Packet *p = t->pkt();
00313       if (verbose)
00314     agent_->trace("T %.9f _%d_ dstQ id %d delete seq %d",
00315               CURRENT_TIME, ipaddr_, dst, t->seqno());
00316       Packet::free(p);
00317       d->delEntry(t); 
00318       agent_->stats.num_reseqq_drops++;
00319     }
00320 
00321   LIST_REMOVE(d,link);
00322   delete d;
00323 }
00324 
00325 void
00326 dstQueue::dumpAll()
00327 {
00328     dstent *t;
00329 
00330     for(t = dstentHead.lh_first; t; t = t->link.le_next) {
00331       if (verbose)
00332         agent_->trace("T %.9f _%d_ dest_queue - src %d expire %.9f seqno %d",
00333                   CURRENT_TIME, ipaddr_, t->ipaddr(), t->expire(), t->seqno());
00334 
00335         txent *u = t->findFirstEntry();
00336         for(;u; u = u->link.le_next) {
00337           if(verbose)
00338             agent_->trace("T %.9f _%d_ dest_queue - src %d seq %d expire %.9f",
00339                   CURRENT_TIME, ipaddr_, t->ipaddr(),
00340                   u->seqno(), u->expire());
00341         }
00342     }
00343 }

Generated on Tue Mar 6 16:47:44 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6