semantic-packetqueue.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:9k
- /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
- /*
- * Copyright (c) 1997 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the Daedalus Research
- * Group at the University of California at Berkeley.
- * 4. Neither the name of the University nor of the Research Group may be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * semantic-packetqueue.cc: contributed by the Daedalus Research Group,
- * UC Berkeley (http://daedalus.cs.berkeley.edu).
- */
- #include "ip.h"
- #include "tcp.h"
- #include "template.h"
- #include "semantic-packetqueue.h"
- #include "ack-recons.h"
- static class SemanticPacketQueueClass : public TclClass {
- public:
- SemanticPacketQueueClass() : TclClass("PacketQueue/Semantic") {}
- TclObject* create(int , const char*const*) {
- return (new SemanticPacketQueue());
- }
- } class_semanticpacketqueue;
- SemanticPacketQueue::SemanticPacketQueue() : ack_count(0), data_count(0),
- acks_to_send(0), marked_count_(0), unmarked_count_(0)
- {
- bind_bool("acksfirst_", &acksfirst_);
- bind_bool("filteracks_", &filteracks_);
- bind_bool("reconsAcks_", &reconsAcks_);
- bind_bool("replace_head_", &replace_head_);
- bind_bool("priority_drop_", &priority_drop_);
- bind_bool("random_drop_", &random_drop_);
- bind_bool("random_ecn_", &random_ecn_);
- }
- int
- SemanticPacketQueue::command(int argc, const char*const* argv)
- {
- if (argc == 3) {
- if (strcmp(argv[1], "ackrecons") == 0) {
- if ((reconsCtrl_ = (AckReconsController *)
- TclObject::lookup(argv[2]))) {
- reconsCtrl_->spq_ = this;
- reconsAcks_ = 1;
- }
- }
- return (TCL_OK);
- }
- return (TclObject::command(argc, argv));
- }
- /*
- * Deque TCP acks before any other type of packet.
- */
- Packet*
- SemanticPacketQueue::deque_acksfirst() {
- Packet* p = head_;
- Packet* pp = NULL;
- packet_t type;
- if (ack_count > 0) {
- while (p) {
- type = hdr_cmn::access(p)->ptype_;
- if (type == PT_ACK)
- break;
- pp = p;
- p = p->next_;
- }
- if (!p)
- fprintf(stderr, "In deque_acksfirst(): ack_count: %d but no acks in queue, length = %dn", ack_count, length());
- PacketQueue::remove(p, pp);
- } else {
- p = PacketQueue::deque();
- }
- return p;
- }
- /*
- * Purge the queue of acks that are older (i.e., have a smaller sequence
- * number) than the most recent ack. If replace_head is set, the most recent
- * ack (pointed to by pkt) takes the place of the oldest ack that is purged.
- * Otherwise, it remains at the tail of the queue. pkt must be an ACK -- this
- * is checked by the caller.
- */
- void
- SemanticPacketQueue::filterAcks(Packet *pkt, int replace_head)
- {
- int done_replacement = 0;
- Packet *p, *pp, *new_p;
- hdr_tcp *tcph = hdr_tcp::access(pkt);
- int &ack = tcph->seqno();
- hdr_ip *iph = hdr_ip::access(pkt);
- for (p = head(), pp = p; p != 0; ) {
- /*
- * Check if packet in the queue belongs to the
- * same connection as the most recent ack
- */
- if (compareFlows(hdr_ip::access(p), iph)) {
- /* check if queued packet is an ack */
- if (hdr_cmn::access(p)->ptype_==PT_ACK) {
- hdr_tcp *th = hdr_tcp::access(p);
- /* is this ack older than the current one? */
- if ((th->seqno() < ack) ||
- (replace_head && th->seqno() == ack)) {
- /*
- * If we haven't yet replaced the ack
- * closest to the head with the most
- * recent ack, do so now.
- */
- if (replace_head && pkt != p &&
- !done_replacement) {
- PacketQueue::remove(pkt);
- ack_count--; /* XXX */
- pkt->next_ = p;
- if (pp)
- pp->next_ = pkt;
- pp = pkt;
- done_replacement = 1;
- continue;
- } else if (done_replacement||pkt != p){
- new_p = p->next_;
- /*
- * If p is in scheduler queue,
- * cancel the event. Also,
- * print out a warning because
- * this should never happen.
- */
- Scheduler &s = Scheduler::instance();
- if (s.lookup(p->uid_)) {
- s.cancel(p);
- fprintf(stderr, "Warning: In filterAcks(): packet being dropped from queue is in scheduler queuen");
- }
- PacketQueue::remove(p, pp);
- /* XXX should drop, but we
- don't have access to q */
- Packet::free(p);
- ack_count--;
- p = new_p;
- continue;
- }
- if (ack_count <= 0)
- fprintf(stderr,
- "oops! ackcount %dn",
- ack_count);
- }
- }
- }
- pp = p;
- p = p->next_;
- }
- }
- /* check if packet is marked */
- int
- SemanticPacketQueue::isMarked(Packet *p)
- {
- return (hdr_flags::access(p)->fs_);
- }
- /* pick out the index'th of the appropriate kind (marked/unmarked) depending on markedFlag */
- Packet*
- SemanticPacketQueue::lookup(int index, int markedFlag)
- {
- if (index < 0) {
- fprintf(stderr, "In SemanticPacketQueue::lookup(): index = %dn", index);
- return (NULL);
- }
- for (Packet* p = head_; p != 0; p = p->next_) {
- if (isMarked(p) == markedFlag)
- if (--index < 0)
- return (p);
- }
- return (NULL);
- }
- /*
- * If random_ecn_ is set, pick out the packet for ECN at random from among the
- * packets in the queue and the packet that just arrived ('pkt'). Otherwise, just
- * pick the packet that just arrived.
- */
- Packet*
- SemanticPacketQueue::pickPacketForECN(Packet* pkt)
- {
- Packet *victim;
- int victimIndex;
- if (random_ecn_) {
- victimIndex = Random::integer(length()+1);
- if (victimIndex == length())
- victim = pkt;
- else
- victim = PacketQueue::lookup(victimIndex);
- }
- else
- victim = pkt;
- return (victim);
- }
-
- /*
- * If priority_drop_ is set, drop marked packets before unmarked ones.
- * If in addition or separately random_drop_ is set, use randomization in
- * picking out the victim. XXX not used at present
- */
- Packet*
- SemanticPacketQueue::pickPacketToDrop()
- {
- Packet *victim;
- int victimIndex, victimMarked;
- if (!priority_drop_) {
- if (random_drop_)
- victim=PacketQueue::lookup(Random::integer(length()));
- else
- victim = PacketQueue::lookup(length() - 1);
- } else {
- /* if there are marked (low priority) packets */
- if (marked_count_) {
- victimMarked = 1;
- if (!random_drop_)
- victimIndex = marked_count_ - 1;
- else
- victimIndex = Random::integer(marked_count_);
- }
- else {
- victimMarked = 0;
- if (!random_drop_)
- victimIndex = unmarked_count_ - 1;
- else
- victimIndex = Random::integer(unmarked_count_);
- }
- victim = lookup(victimIndex, victimMarked);
- }
- return (victim);
- }
-
- Packet*
- SemanticPacketQueue::enque(Packet *pkt)
- {
- if (reconsAcks_&&(hdr_cmn::access(pkt)->ptype_==PT_ACK)) {
- reconsCtrl_->recv(pkt);
- return NULL;
- }
- if (hdr_cmn::access(pkt)->ptype_ == PT_ACK)
- ack_count++;
- else
- data_count++;
- if (isMarked(pkt))
- marked_count_++;
- else
- unmarked_count_++;
- Packet* pt = PacketQueue::enque(pkt); /* actually enque the packet */
- if (filteracks_ && (hdr_cmn::access(pkt)->ptype_==PT_ACK))
- filterAcks(pkt, replace_head_);
- return pt;
- }
- Packet *
- SemanticPacketQueue::deque()
- {
- Packet *pkt;
- if (acksfirst_)
- pkt = deque_acksfirst();
- else
- pkt = PacketQueue::deque();
-
- if (pkt) {
- if (hdr_cmn::access(pkt)->ptype_ == PT_ACK)
- ack_count--;
- else
- data_count--;
- if (isMarked(pkt))
- marked_count_--;
- else
- unmarked_count_--;
- }
- return pkt;
- }
- void
- SemanticPacketQueue::remove(Packet *pkt)
- {
- PacketQueue::remove(pkt);
- if (pkt) {
- if (hdr_cmn::access(pkt)->ptype_ == PT_ACK)
- ack_count--;
- else
- data_count--;
- if (isMarked(pkt))
- marked_count_--;
- else
- unmarked_count_--;
- }
- }