Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

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 Apr 20 12:14:31 2004 for NS2.26SourcesOriginal by doxygen 1.3.3