semantic-packetqueue.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 The 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 Daedalus Research
00017  *  Group at the University of California at Berkeley.
00018  * 4. Neither the name of the University nor of the Research Group 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  * semantic-packetqueue.cc: contributed by the Daedalus Research Group, 
00035  * UC Berkeley (http://daedalus.cs.berkeley.edu).
00036  */
00037 
00038 #include "ip.h"
00039 #include "tcp.h"
00040 #include "template.h"
00041 #include "semantic-packetqueue.h"
00042 #include "ack-recons.h"
00043 
00044 static class SemanticPacketQueueClass : public TclClass {
00045 public:
00046     SemanticPacketQueueClass() : TclClass("PacketQueue/Semantic") {}
00047     TclObject* create(int , const char*const*) {
00048         return (new SemanticPacketQueue());
00049     }
00050 } class_semanticpacketqueue;
00051 
00052 SemanticPacketQueue::SemanticPacketQueue() : ack_count(0), data_count(0), 
00053     acks_to_send(0), marked_count_(0), unmarked_count_(0) 
00054 {
00055     bind_bool("acksfirst_", &acksfirst_);
00056     bind_bool("filteracks_", &filteracks_);
00057     bind_bool("reconsAcks_", &reconsAcks_);
00058     bind_bool("replace_head_", &replace_head_);
00059     bind_bool("priority_drop_", &priority_drop_);
00060     bind_bool("random_drop_", &random_drop_);
00061     bind_bool("random_ecn_", &random_ecn_);
00062 }   
00063 
00064 int
00065 SemanticPacketQueue::command(int argc, const char*const* argv)
00066 {
00067     if (argc == 3) {
00068         if (strcmp(argv[1], "ackrecons") == 0) {
00069             if ((reconsCtrl_ = (AckReconsController *) 
00070                  TclObject::lookup(argv[2]))) {
00071                 reconsCtrl_->spq_ = this;
00072                 reconsAcks_ = 1;
00073             }
00074         }
00075         return (TCL_OK);
00076     }
00077     return (TclObject::command(argc, argv));
00078 }
00079 
00080 /* 
00081  * Deque TCP acks before any other type of packet.
00082  */
00083 Packet* 
00084 SemanticPacketQueue::deque_acksfirst() {
00085     Packet* p = head_;
00086     Packet* pp = NULL;
00087     packet_t type;
00088 
00089     if (ack_count > 0) {
00090         while (p) {
00091             type = hdr_cmn::access(p)->ptype_;
00092             if (type == PT_ACK)
00093                 break;
00094             pp = p;
00095             p = p->next_;
00096         }
00097         if (!p) 
00098             fprintf(stderr, "In deque_acksfirst(): ack_count: %d but no acks in queue, length = %d\n", ack_count, length());
00099         PacketQueue::remove(p, pp);
00100     } else {
00101         p = PacketQueue::deque();
00102     }
00103     return p;
00104 }
00105 
00106 /*
00107  * Purge the queue of acks that are older (i.e., have a smaller sequence 
00108  * number) than the most recent ack. If replace_head is set, the most recent
00109  * ack (pointed to by pkt) takes the place of the oldest ack that is purged. 
00110  * Otherwise, it remains at the tail of the queue.  pkt must be an ACK -- this
00111  * is checked by the caller.
00112  */
00113 void
00114 SemanticPacketQueue::filterAcks(Packet *pkt, int replace_head) 
00115 {
00116     int done_replacement = 0;
00117 
00118     Packet *p, *pp, *new_p;
00119     hdr_tcp *tcph = hdr_tcp::access(pkt);
00120     int &ack = tcph->seqno();
00121 
00122     hdr_ip *iph = hdr_ip::access(pkt);
00123     for (p = head(), pp = p; p != 0; ) {
00124         /* 
00125          * Check if packet in the queue belongs to the 
00126          * same connection as the most recent ack
00127          */
00128         if (compareFlows(hdr_ip::access(p), iph)) {
00129             /* check if queued packet is an ack */
00130             if (hdr_cmn::access(p)->ptype_==PT_ACK) {
00131                 hdr_tcp *th = hdr_tcp::access(p);
00132                 /* is this ack older than the current one? */
00133                 if ((th->seqno() < ack) ||
00134                     (replace_head && th->seqno() == ack)) { 
00135                     /* 
00136                      * If we haven't yet replaced the ack 
00137                      * closest to the head with the most 
00138                      * recent ack, do so now.
00139                      */
00140                     if (replace_head && pkt != p &&
00141                         !done_replacement) {
00142                         PacketQueue::remove(pkt);
00143                         ack_count--; /* XXX */
00144                         pkt->next_ = p;
00145                         if (pp)
00146                             pp->next_ = pkt;
00147                         pp = pkt;
00148                         done_replacement = 1;
00149                         continue;
00150                     } else if (done_replacement||pkt != p){
00151                         new_p = p->next_;
00152                         /* 
00153                          * If p is in scheduler queue,
00154                          * cancel the event. Also, 
00155                          * print out a warning because
00156                          * this should never happen.
00157                          */
00158                         Scheduler &s = Scheduler::instance();
00159                         if (s.lookup(p->uid_)) {
00160                             s.cancel(p);
00161                             fprintf(stderr, "Warning: In filterAcks(): packet being dropped from queue is in scheduler queue\n");
00162                         }
00163                         PacketQueue::remove(p, pp);
00164                         /* XXX should drop, but we
00165                            don't have access to q */
00166                         Packet::free(p); 
00167                         ack_count--;
00168                         p = new_p;
00169                         continue;
00170                     }
00171                     if (ack_count <= 0)
00172                         fprintf(stderr, 
00173                             "oops! ackcount %d\n",
00174                             ack_count);
00175                 }
00176             }
00177         }
00178         pp = p;
00179         p = p->next_;
00180     }
00181 }
00182 
00183 /* check if packet is marked */
00184 int
00185 SemanticPacketQueue::isMarked(Packet *p) 
00186 {
00187     return (hdr_flags::access(p)->fs_);
00188 }
00189 
00190 
00191 /* pick out the index'th of the appropriate kind (marked/unmarked) depending on markedFlag */
00192 Packet*
00193 SemanticPacketQueue::lookup(int index, int markedFlag) 
00194 {
00195     if (index < 0) {
00196         fprintf(stderr, "In SemanticPacketQueue::lookup(): index = %d\n", index);
00197         return (NULL);
00198     }
00199     for (Packet* p = head_; p != 0; p = p->next_) {
00200         if (isMarked(p) == markedFlag)
00201             if (--index < 0)
00202                 return (p);
00203     }
00204     return (NULL);
00205 }
00206 
00207 /*
00208  * If random_ecn_ is set, pick out the packet for ECN at random from among the
00209  * packets in the queue and the packet that just arrived ('pkt'). Otherwise, just
00210  * pick the packet that just arrived.
00211  */
00212 Packet*
00213 SemanticPacketQueue::pickPacketForECN(Packet* pkt) 
00214 {
00215     Packet *victim;
00216     int victimIndex;
00217 
00218     if (random_ecn_) {
00219         victimIndex = Random::integer(length()+1);
00220         if (victimIndex == length())
00221             victim = pkt;
00222         else
00223             victim = PacketQueue::lookup(victimIndex);
00224     }
00225     else 
00226         victim = pkt;
00227     return (victim);
00228 }
00229         
00230 
00231 /* 
00232  * If priority_drop_ is set, drop marked packets before unmarked ones.
00233  * If in addition or separately random_drop_ is set, use randomization in
00234  * picking out the victim. XXX not used at present 
00235  */
00236 Packet*
00237 SemanticPacketQueue::pickPacketToDrop()
00238 {
00239     Packet *victim;
00240     int victimIndex, victimMarked;
00241 
00242     if (!priority_drop_) {
00243         if (random_drop_)
00244             victim=PacketQueue::lookup(Random::integer(length()));
00245         else
00246             victim = PacketQueue::lookup(length() - 1);
00247     } else {
00248         /* if there are marked (low priority) packets */
00249         if (marked_count_) {
00250             victimMarked = 1;
00251             if (!random_drop_) 
00252                 victimIndex = marked_count_ - 1;
00253             else
00254                 victimIndex = Random::integer(marked_count_);
00255         }
00256         else {
00257             victimMarked = 0;
00258             if (!random_drop_)
00259                 victimIndex = unmarked_count_ - 1;
00260             else
00261                 victimIndex = Random::integer(unmarked_count_);
00262         }
00263         victim = lookup(victimIndex, victimMarked);
00264     }
00265     return (victim);
00266 }
00267                 
00268 Packet*
00269 SemanticPacketQueue::enque(Packet *pkt)
00270 {
00271     if (reconsAcks_&&(hdr_cmn::access(pkt)->ptype_==PT_ACK)) {
00272         reconsCtrl_->recv(pkt);
00273         return NULL;
00274     }
00275     if (hdr_cmn::access(pkt)->ptype_ == PT_ACK)
00276         ack_count++;
00277     else
00278         data_count++;
00279     if (isMarked(pkt)) 
00280         marked_count_++;
00281     else
00282         unmarked_count_++;
00283 
00284     Packet* pt = PacketQueue::enque(pkt); /* actually enque the packet */
00285 
00286     if (filteracks_ && (hdr_cmn::access(pkt)->ptype_==PT_ACK))
00287         filterAcks(pkt, replace_head_);
00288     return pt;
00289 }
00290 
00291 Packet *
00292 SemanticPacketQueue::deque()
00293 {
00294     Packet *pkt;
00295 
00296     if (acksfirst_)
00297         pkt = deque_acksfirst();
00298     else
00299         pkt = PacketQueue::deque();
00300     
00301     if (pkt) {
00302         if (hdr_cmn::access(pkt)->ptype_ == PT_ACK)
00303             ack_count--;
00304         else
00305             data_count--;
00306         if (isMarked(pkt))
00307             marked_count_--;
00308         else
00309             unmarked_count_--;
00310     }
00311     return pkt;
00312 }
00313 
00314 void 
00315 SemanticPacketQueue::remove(Packet *pkt)
00316 {
00317     PacketQueue::remove(pkt);
00318     if (pkt) {
00319         if (hdr_cmn::access(pkt)->ptype_ == PT_ACK)
00320             ack_count--;
00321         else
00322             data_count--;
00323         if (isMarked(pkt))
00324             marked_count_--;
00325         else
00326             unmarked_count_--;
00327     }
00328 }
00329 

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