INET Framework for OMNeT++/OMNEST
AnsaQosSystem.cc
Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2011 Martin Danko
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 //
00018 
00019 
00020 #include <omnetpp.h>
00021 #include "AnsaQosSystem.h"
00022 #include "RoutingTableAccess.h"
00023 
00024 
00025 Define_Module(AnsaQosSystem);
00026 
00027 /*
00028  * ~AnsaQosSystem(): 
00029  * Destruktor modulu, ktory odstrani vsetky pakety v podfrontach.
00030  */
00031  
00032 AnsaQosSystem::~AnsaQosSystem()
00033 {
00034   for (AnsaSubQueues::iterator sbqIt = subQueues.begin(); sbqIt != subQueues.end(); ++sbqIt)
00035   {
00036     sbqIt->clearSubQueue();
00037   }
00038   
00039   delete[] subqlenVec;
00040   delete[] subdropVec;
00041 }
00042 
00043 /*
00044  * initialize(): 
00045  * Metoda pre inicializaciu modulu.
00046  * @param stage - aktualna sekvencia volania
00047  */
00048 
00049 void AnsaQosSystem::initialize(int stage)
00050 {
00051   if(stage == 0)
00052   {
00053     PassiveQueueBase::initialize();
00054 
00055     outGate = gate("out");
00056     
00057     WATCH(QueueInfo);
00058     WATCH_VECTOR(subQueues);
00059   }
00060   else if (stage == 4)
00061   {
00062     // nacitanie konfiguracie zo XML
00063     loadConfigFromXML();
00064   }
00065 
00066 }
00067 
00068 /*
00069  * loadConfigFromXML(): 
00070  * Metoda pre nacitanie konfiguracie modulu zo XML.
00071  */
00072  
00073 void AnsaQosSystem::loadConfigFromXML()
00074 {
00075   IRoutingTable* rt = RoutingTableAccess().get();
00076   
00077   const char *fileName = par("configFile");
00078   cXMLElement* document = ev.getXMLDocument(fileName);
00079   if (document == NULL)
00080   { 
00081     error("Cannot read AS configuration from file %s", fileName);
00082   }
00083   /* Ziskanie elementu konfiguracie daneho smerovaca */
00084   std::string routerXPath("Router[@id='");
00085   std::string routerId = rt->getRouterId().str();
00086   routerXPath += routerId;
00087   routerXPath += "']";
00088  
00089   cXMLElement* router = document->getElementByPath(routerXPath.c_str());
00090   if (router == NULL)
00091   {
00092     error("No configuration for Router ID: %s", routerId.c_str());
00093   }
00094 
00095   /* Ziskanie elementu konfiguracie daneho rozhrania */
00096   std::string itfName = this->getParentModule()->getName();
00097   itfName += (char)('0' + this->getParentModule()->getIndex());
00098   std::string intXPath(".//Interface[@name='");
00099   intXPath += itfName;
00100   intXPath += "']";
00101 
00102   cXMLElement* qInt = router->getElementByPath(intXPath.c_str());
00103   if (qInt == NULL)
00104   {
00105     error("No configuration for Interface: %s", itfName.c_str());
00106   }
00107   
00108   /* Ziskanie elementu konfiguracie vystupnej fronty */
00109   cXMLElement* clsfrEl =  NULL;
00110   cXMLElement* qs = qInt->getFirstChildWithTag("OutputQueue");
00111   if (qs == NULL)
00112   { // ziadna konfiguracia -> defaultne FIFO o dlzke 75
00113     QueueInfo.setFIFO(75);
00114     subQueues.push_back(ANSAQOS::SubQueue(ANSAQOS::Q_FIFO, ANSAQOS::S_FIFO, QueueInfo.getHoldCapacity(), *clsfrEl));
00115     return;
00116   }
00117  
00118   /* Nacitanie konfiguracie podla typu fronty */
00119   std::string qType = qs->getAttribute("type");
00120   if(qType == "WFQ")
00121   {
00122     QueueInfo.setWFQ();
00123     cXMLElementList ifDetails = qs->getChildren();
00124     for (cXMLElementList::iterator ifElemIt = ifDetails.begin(); ifElemIt != ifDetails.end(); ++ifElemIt) 
00125     {
00126       std::string nodeName = (*ifElemIt)->getTagName();
00127       if (nodeName == "HoldQueueLength")
00128         QueueInfo.setHoldCapacity(atoi((*ifElemIt)->getNodeValue()));
00129       if (nodeName == "CDT")
00130         QueueInfo.setCdt(atoi((*ifElemIt)->getNodeValue()));
00131       if (nodeName == "DynamicQueues")
00132         QueueInfo.setMaxQueues(atoi((*ifElemIt)->getNodeValue()));
00133     }
00134   }
00135   else if(qType == "FIFO")
00136   {
00137     int len = 75;
00138     cXMLElementList ifDetails = qs->getChildren();
00139     for (cXMLElementList::iterator ifElemIt = ifDetails.begin(); ifElemIt != ifDetails.end(); ++ifElemIt) 
00140     {
00141       std::string nodeName = (*ifElemIt)->getTagName();
00142       if (nodeName == "HoldQueueLength")
00143         len = atoi((*ifElemIt)->getNodeValue());
00144     }
00145     QueueInfo.setFIFO(len);
00146     subQueues.push_back(ANSAQOS::SubQueue(ANSAQOS::Q_FIFO, ANSAQOS::S_FIFO, QueueInfo.getHoldCapacity(), *clsfrEl));
00147   }
00148   else if(qType == "PQ")
00149   {
00150     QueueInfo.setPQ();
00151 
00152     cXMLElement* pql = qs->getFirstChildWithTag("PriorityQueueList");
00153     if (pql == NULL)
00154     {
00155       error("No priority-list specified on interface: %s", itfName.c_str());
00156     }
00157     
00158     QueueInfo.setListId(pql->getNodeValue());
00159     std::string pqlXPath(".//PriorityQueueList[@id='");
00160     pqlXPath += QueueInfo.getListId();
00161     pqlXPath += "']";
00162 
00163     
00164 
00165     pql = router->getElementByPath(pqlXPath.c_str());
00166     if (pql == NULL)
00167     {
00168       error("Priority-list %s is not defined", QueueInfo.getListId().c_str());
00169     }
00170     initSubQueueVectors(ANSAQOS::Q_PQ);
00171     setPQSubQueue ("HighQueue", pql, 20);
00172     setPQSubQueue ("MediumQueue", pql, 40);
00173     setPQSubQueue ("NormalQueue", pql, 60);
00174     setPQSubQueue ("LowQueue", pql, 80);       
00175   }
00176   else if(qType == "CQ")
00177   {
00178     QueueInfo.setCQ();
00179 
00180     cXMLElement* pql = qs->getFirstChildWithTag("CustomQueueList");
00181     if (pql == NULL)
00182     {
00183       error("No custom-list specified on interface: %s", itfName.c_str());
00184     }
00185     
00186     QueueInfo.setListId(pql->getNodeValue());
00187     std::string pqlXPath(".//CustomQueueList[@id='");
00188     pqlXPath += QueueInfo.getListId();
00189     pqlXPath += "']";
00190 
00191     pql = router->getElementByPath(pqlXPath.c_str());
00192     if (pql == NULL)
00193     {
00194       error("Custom-list %s is not defined", QueueInfo.getListId().c_str());
00195     }
00196     
00197     initSubQueueVectors(ANSAQOS::Q_CQ);
00198     for(int i = 0; i < 16; ++i)
00199       setCQSubQueue (i+1, pql);
00200   }
00201    
00202 }
00203 
00204 /*
00205  * setPQSubQueue(): 
00206  * Metoda nacita konfiguraciu a vytvori podfrontu PQ 
00207  * @param id - identifikator podfronty
00208  * @param pql - XML blok s konfiguracou vystupnej fronty 
00209  */
00210 
00211 void AnsaQosSystem::setPQSubQueue (std::string id, cXMLElement* pql, int len)
00212 {
00213     cXMLElement* clsfr = NULL;
00214     std::string elemDQ;
00215     
00216     cXMLElementList pqlDetails = pql->getChildren();
00217     for (cXMLElementList::iterator pqlElemIt = pqlDetails.begin(); pqlElemIt != pqlDetails.end(); ++pqlElemIt) 
00218     {
00219       std::string nodeName = (*pqlElemIt)->getTagName();
00220       if (nodeName == "DefaultQueue")
00221          elemDQ = (*pqlElemIt)->getNodeValue();
00222       if (nodeName == id)
00223       {
00224         cXMLElementList qDetails = (*pqlElemIt)->getChildren();
00225         for (cXMLElementList::iterator qElemIt = qDetails.begin(); qElemIt != qDetails.end(); ++qElemIt)
00226         {
00227           std::string nn = (*qElemIt)->getTagName();
00228           if (nn == "Lenght")
00229             len = atoi((*qElemIt)->getNodeValue());
00230           if (nn == "Classifier")
00231             clsfr = *qElemIt;
00232         } 
00233       }
00234     }
00235     
00236     subQueues.push_back(ANSAQOS::SubQueue(ANSAQOS::Q_PQ, ANSAQOS::S_FIFO, len, *clsfr));
00237     int d = subQueues.size();
00238     subQueues.back().setQueueId(d);
00239     subQueues.back().setVectorPointer(&subqlenVec[d-1], &subdropVec[d-1]);
00240     QueueInfo.addHoldCapacity(len);
00241 
00242     if (elemDQ.length() > 0 && elemDQ[2] == id[2])
00243        QueueInfo.setDefaultQueueId(subQueues.size());
00244   
00245     
00246 }
00247 
00248 /*
00249  * setCQSubQueue(): 
00250  * Metoda nacita konfiguraciu a vytvori podfrontu CQ 
00251  * @param id - identifikator podfronty
00252  * @param pql - XML blok s konfiguracou vystupnej fronty 
00253  */
00254 
00255 void AnsaQosSystem::setCQSubQueue (int id, cXMLElement* pql)
00256 {
00257     cXMLElement* clsfr = NULL;
00258     int dqVal;
00259     int len = 20;
00260     int bc = 1500;
00261     
00262     cXMLElementList pqlDetails = pql->getChildren();
00263     for (cXMLElementList::iterator pqlElemIt = pqlDetails.begin(); pqlElemIt != pqlDetails.end(); ++pqlElemIt) 
00264     {
00265       std::string nodeName = (*pqlElemIt)->getTagName();
00266       if (nodeName == "DefaultQueue")
00267          dqVal = atoi((*pqlElemIt)->getNodeValue());
00268       if (nodeName == "CustomQueue" && atoi((*pqlElemIt)->getAttribute("id")) == id)
00269       {
00270         cXMLElementList qDetails = (*pqlElemIt)->getChildren();
00271         for (cXMLElementList::iterator qElemIt = qDetails.begin(); qElemIt != qDetails.end(); ++qElemIt)
00272         {
00273           std::string nn = (*qElemIt)->getTagName();
00274           if (nn == "Lenght")
00275             len = atoi((*qElemIt)->getNodeValue());
00276           if (nn == "ByteCount")
00277             bc = atoi((*qElemIt)->getNodeValue());
00278           if (nn == "Classifier")
00279             clsfr = *qElemIt;
00280         } 
00281       }
00282     }
00283     
00284     subQueues.push_back(ANSAQOS::SubQueue(ANSAQOS::Q_CQ, ANSAQOS::S_FIFO, len, *clsfr));
00285     subQueues.back().setQueueId(id);
00286     subQueues.back().setWeight(bc);
00287     subQueues.back().setActualBytes(bc);
00288     subQueues.back().setVectorPointer(&subqlenVec[id-1], &subdropVec[id-1]);
00289     QueueInfo.addHoldCapacity(len);
00290 
00291     if (dqVal == id)
00292        QueueInfo.setDefaultQueueId(id);
00293    
00294 }
00295 
00296 /*
00297  * getLowestSn(): 
00298  * Funkcia najde najnizsie sekvencne cislo vramci vsetkych podfront. 
00299  * @return - Vrati hodnotu najnizsieho sekvencneho cisla
00300  */
00301 
00302 int AnsaQosSystem::getLowestSn()
00303 {
00304     int sn = -1;
00305     
00306     for (AnsaSubQueues::iterator sbqIt = subQueues.begin(); sbqIt != subQueues.end(); ++sbqIt)
00307     {
00308       if(sn == -1 && !sbqIt->isQueueEmpty())
00309       {
00310         sn = sbqIt->getLowestSn();
00311       }
00312       else if(!sbqIt->isQueueEmpty() && sbqIt->getLowestSn() < sn )
00313       {
00314         sn = sbqIt->getLowestSn();
00315       }
00316     }  
00317     return sn;
00318 }
00319 
00320 
00321 
00322 /*
00323  * initSubQueueVectors(): 
00324  * Funkcia vytvori vektory pre PQ a CQ
00325  * @param sn - typ fronty
00326  */
00327 
00328 void AnsaQosSystem::initSubQueueVectors(ANSAQOS::QueueType type)
00329 {
00330  std::stringstream forStr;
00331  switch(type)
00332   {
00333     case ANSAQOS::Q_PQ :
00334       subqlenVec = new cOutVector[4];
00335       subqlenVec[0].setName("High Length");
00336       subqlenVec[1].setName("Medium Length");
00337       subqlenVec[2].setName("Normal Length");
00338       subqlenVec[3].setName("Low Length");
00339       subdropVec = new cOutVector[4];
00340       subdropVec[0].setName("High Drops");
00341       subdropVec[1].setName("Medium Drops");
00342       subdropVec[2].setName("Normal Drops");
00343       subdropVec[3].setName("Low Drops");  
00344       break;
00345     case ANSAQOS::Q_CQ :
00346       subqlenVec = new cOutVector[16];
00347       subdropVec = new cOutVector[16]; 
00348       for(int i = 0; i < 16; ++i)
00349       {
00350         forStr.str(std::string());
00351         forStr << "Q" << i+1 << " Length";
00352         subqlenVec[i].setName(forStr.str().c_str());
00353         forStr.str(std::string());
00354         forStr << "Q" << i+1 << " Drops";
00355         subdropVec[i].setName(forStr.str().c_str());
00356       }
00357       break;
00358     default :
00359       break;
00360   }  
00361 }
00362 
00363 /*
00364  * getSubQueueBySn(): 
00365  * Funkcia najde frontu obsahujucu paket z danym sekvencnym cislom
00366  * @param sn - sekvencne cislo paketu, ktory ma byt najdeny
00367  * @return - Vrati iterator na frontu s paketom daneho sekvencneho cisla 
00368  */
00369 
00370 AnsaSubQueues::iterator AnsaQosSystem::getSubQueueBySn(int sn)
00371 {
00372     for (AnsaSubQueues::iterator sbqIt = subQueues.begin(); sbqIt != subQueues.end(); ++sbqIt)
00373     {
00374       if(sn == sbqIt->getLowestSn())
00375       {
00376         return sbqIt;
00377       }
00378     }
00379     return subQueues.end();
00380 }
00381 
00382 /*
00383  * substractSnInAllQueues(): 
00384  * Metoda, ktora odcita hodnotu zo sekvencneho cisla paketov vsetkych podfront. 
00385  * @param sn    - hodnota, ktora ma byt zo sekvencnych cisel odcitana 
00386  */
00387 
00388 void AnsaQosSystem::substractSnInAllQueues(int sn)
00389 {
00390     for (AnsaSubQueues::iterator sbqIt = subQueues.begin(); sbqIt != subQueues.end(); ++sbqIt)
00391     {
00392       sbqIt->substractSnFromAll(sn);
00393     }
00394 }
00395 
00396 /*
00397  * enqueue(): 
00398  * Funkcia prevadza operaciu vlozenia spravy do fronty. 
00399  * @param msg   - sprava, ktora ma byt vlozena do fronty
00400  * @return - Vrati true pokial bol paket zahodeny
00401  */
00402 
00403 bool AnsaQosSystem::enqueue(cMessage *msg)
00404 {   
00405     if(QueueInfo.getCurrentHold() < QueueInfo.getHoldCapacity())
00406     { // je miesto vo fronte
00407       for(AnsaSubQueues::iterator sbqIt = subQueues.begin(); sbqIt != subQueues.end(); ++sbqIt)
00408       { // prechadza vsetky podfronty
00409         short res = sbqIt->enqueue(msg,true);
00410         if(res == ANSAQOS::QUEUED)
00411         {
00412           QueueInfo.addCurrentHold();
00413           return false; // paket bol vlozeny do fronty
00414         }
00415         else if(res == ANSAQOS::NOTQUEUED)
00416         {
00417           QueueInfo.addDroped();
00418           delete msg;
00419           return true;  // paket zahodeny lebo sa nevojde do podfronty
00420         }
00421       }
00422       if(QueueInfo.getQueueType() == ANSAQOS::Q_WFQ)
00423       { // vo WFQ neexistuje podfronta pre dany tok
00424         if(QueueInfo.getNumQueues() < QueueInfo.getMaxQueues())
00425         { // je mozne vytvorit podfrontu a vlozit do nej paket 
00426           subQueues.push_back(ANSAQOS::SubQueue(msg, QueueInfo.getCdt()));
00427           QueueInfo.addNumQueues();
00428           QueueInfo.addCurrentHold();
00429           return false;
00430         }
00431       }
00432       else if(QueueInfo.getQueueType() == ANSAQOS::Q_PQ || QueueInfo.getQueueType() == ANSAQOS::Q_CQ)
00433       { // u PQ a CQ moznost vlozenia paketu do defaultnej fronty 
00434         if (subQueues[QueueInfo.getDefaultQueueId()-1].enqueue(msg,false) == ANSAQOS::QUEUED)
00435         {
00436           QueueInfo.addCurrentHold();
00437           return false;
00438         }
00439       }  
00440     }
00441 
00442     QueueInfo.addDroped();
00443     delete msg;  
00444     return true; //paket bol zahodeny
00445 }
00446 
00447 /*
00448  * dequeue(): 
00449  * Funkcia prevadza operaciu vybrania spravy z fronty. 
00450  * @return - Vrati ukazovatel na vybrany paket 
00451  */
00452 
00453 cMessage *AnsaQosSystem::dequeue()
00454 {
00455     if(QueueInfo.getCurrentHold() <= 0)
00456     {
00457         return NULL; // fronta je prazdna
00458     }
00459     
00460     cMessage *msg; cPacket *pkt;
00461     int sn,id;  
00462     AnsaSubQueues::iterator queueIt;
00463     
00464     switch (QueueInfo.getQueueType())
00465     {
00466       /* FIFO fronta ma len jednu "podfrontu" z ktorej sa vyberie prvy paket */
00467       case ANSAQOS::Q_FIFO : 
00468         msg = subQueues.begin()->dequeue();
00469         break;
00470       /* Vo WFQ fronte sa vyberie paket s najmensim sekvencnym cislom.
00471          V pripade, ze podfronta sa vyprazdni, tak je odstranena.
00472          Aby nedoslo k preteceniu hodnoty sekvencneho cisla, tak je po kazdom 
00473          vybrani paketu jeho sekvencne cislo odcitane od ostatnych */
00474       case ANSAQOS::Q_WFQ :
00475         sn = getLowestSn();
00476         queueIt = getSubQueueBySn(sn);
00477                 
00478         msg = queueIt->dequeue();
00479         if(queueIt->isQueueEmpty())
00480         {
00481           subQueues.erase(queueIt);
00482           QueueInfo.remNumQueues();
00483         }
00484         substractSnInAllQueues(getLowestSn());
00485         break;
00486       /* PQ fronta obsahuje 4 fronty, ktore prechadza podla priority
00487          prvy paket, na ktory narazi je vybrany */
00488       case ANSAQOS::Q_PQ :
00489           for (AnsaSubQueues::iterator queueIt = subQueues.begin(); queueIt != subQueues.end(); ++queueIt)
00490           {
00491             if(!queueIt->isQueueEmpty())
00492             {
00493               msg = queueIt->dequeue();
00494               break;
00495             }
00496           }
00497         break;
00498       /* CQ obsahuje 16 front, ktore su prechadzane round robin. 
00499          Pakety su z fronty vyberane az dovtedy, kym obsahuje dostatocny 
00500          pocet bajtov alebo je fronta prazdna*/
00501       case ANSAQOS::Q_CQ :
00502           while (subQueues[QueueInfo.getCurrentCQQueueId()].isQueueEmpty())
00503           { // najdenie prvej neprazdnej fronty
00504             subQueues[QueueInfo.getCurrentCQQueueId()].setActualBytes();
00505             QueueInfo.addCurrentCQQueueId();
00506           }
00507           
00508           id = QueueInfo.getCurrentCQQueueId();
00509           msg = subQueues[id].dequeue(); // vybranie paketu z fronty
00510           pkt = dynamic_cast<cPacket *> (msg->dup());
00511           subQueues[id].remActualBytes(pkt->getByteLength()); // odstanenie bajtov z fronty
00512           delete pkt;
00513           
00514           if(subQueues[id].getActualBytes() <= 0)
00515           { // nedostatocny pocet bajtov.. prechod na dalsiu frontu a reset bajtov
00516             subQueues[id].setActualBytes();
00517             QueueInfo.addCurrentCQQueueId();  
00518           }
00519         break; 
00520       default :
00521         msg = NULL;
00522         break;
00523     }
00524 
00525     QueueInfo.remCurrentHold();
00526     return msg;
00527 }
00528 
00529 /*
00530  * sendOut(): 
00531  * Metoda odosle spravu cez vystupnu branu
00532  * @param msg - sprava, ktora ma byt odoslana
00533  */
00534 
00535 void AnsaQosSystem::sendOut(cMessage *msg)
00536 {
00537     send(msg, outGate);
00538 }
00539 
00540 /*
00541  * SubQueue(): 
00542  * Konstruktor vytvorenia podfronty pre WFQ na zaklade spravy
00543  * @param msg - sprava, ktora definuje tok pre klasifikator podfronty
00544  * @param cdt - dlzka vytvaranej fronty 
00545  */
00546 
00547 ANSAQOS::SubQueue::SubQueue(cMessage *msg, int cdt)
00548 {
00549   qlenVec = dropVec = NULL;
00550   lastSn = 0;
00551   maxLength = cdt;
00552   qt = Q_WFQ;
00553   sbqt = S_FIFO;
00554   droped = 0;
00555   this->setWeight(msg);
00556   clsfr = new WFQClassifier(msg);
00557   this->enqueue(msg,true);
00558 }
00559 
00560 /*
00561  * SubQueue(): 
00562  * Konstruktor pre vytvorenie podfronty na zaklade vstupnych parametrov
00563  * @param t1 - typ fronty, ktorej je podfronta sucastou
00564  * @param t2 - typ podfronty
00565  * @param len - dlzka vytvaranej fronty   
00566  * @param clsfrConfig - XML blok s konfiguraciu klasifikatora podfronty
00567  */
00568 
00569 ANSAQOS::SubQueue::SubQueue(QueueType t1, SubQueueType t2, int len, cXMLElement& clsfrConfig)
00570 {
00571   qlenVec = dropVec = NULL;
00572   lastSn = 0;
00573   maxLength = len;
00574   qt = t1;
00575   sbqt = t2;
00576   droped = 0;
00577   
00578   switch (qt) // na zaklade typu fronty sa vytvori klasifikator podfronty
00579   {
00580     case Q_FIFO : 
00581       clsfr = new MatchAnyClassifier();
00582       break;
00583     case Q_PQ :
00584     case Q_CQ :
00585       if (&clsfrConfig != NULL)
00586       {
00587         std::string cType = clsfrConfig.getAttribute("type");
00588         if(cType == "DSCP")
00589           clsfr = new DSCPClassifier(clsfrConfig);
00590         else if (cType == "PREC")
00591           clsfr = new PRECClassifier(clsfrConfig);
00592         else if (cType == "ACL")
00593           clsfr = new ACLClassifier(clsfrConfig);   
00594       }
00595       else
00596         clsfr = new MatchNoneClassifier();
00597       break;
00598     default :
00599       break;
00600   }
00601   
00602 }
00603 
00604 /*
00605  * clearSubQueue(): 
00606  * Metoda vymaze vsetky pakety z podfronty. 
00607  */
00608 
00609 void ANSAQOS::SubQueue::clearSubQueue()
00610 {
00611     if(!isQueueEmpty())
00612     {
00613         for (std::vector<SNPacket>::iterator it = snPackets.begin(); it!=snPackets.end(); ++it)
00614         {
00615             delete it->getMsg();
00616             it->setMsg(NULL);
00617         }
00618     }    
00619 }
00620 
00621 /*
00622  * enqueue(): 
00623  * Funkcia prevadza operaciu vlozenia spravy do subfronty. 
00624  * @param msg   - sprava, ktora ma byt vlozena do subfronty
00625  * @param classify - parameter urcujuci ci sa ma vykonat klasifikacia 
00626  * @return - Vrati vysledok operacie 
00627  */
00628 
00629 short ANSAQOS::SubQueue::enqueue(cMessage *msg, bool classify)
00630 {
00631   int sn = 0;
00632   
00633   if(classify && !clsfr->classifyPacket(msg))
00634     return NOMATCH; // paket nebol do fronty klasifikovany
00635   
00636   if(this->getQueueLength() >= maxLength)
00637   {
00638     this->addDroped();
00639     this->updateVectorDrop();
00640     return NOTQUEUED; // fronta je plna
00641   }  
00642   
00643   switch (qt)
00644   {
00645     case Q_WFQ : 
00646       sn = this->calculateSn(msg); // vypocet SN v pripade WFQ fronty
00647       setLastSn(sn);
00648       break;
00649     default :
00650       break;  
00651   }
00652   
00653   SNPacket newSNPacket(msg, sn);
00654   snPackets.push_back(newSNPacket); // vlozenie paketu do podfronty
00655   
00656   this->updateVectorLenght();
00657   return QUEUED;  // paket vlozeny do fronty
00658 }
00659 
00660 /*
00661  * dequeue(): 
00662  * Funkcia vyberie sparavy z podfronty
00663  * @return - Vrati vybranu spravu  
00664  */
00665 
00666 cMessage *ANSAQOS::SubQueue::dequeue()
00667 {
00668     cMessage *msg = (snPackets.front()).getMsg();
00669     snPackets.erase(snPackets.begin());
00670     
00671     this->updateVectorLenght();
00672     return msg;
00673 }
00674 
00675 /*
00676  * calculateSn(): 
00677  * Funkcia vypocita sekvencne cislo pre spravu na zaklade 
00678  * hodnoty jej IP precedence a velkosti. 
00679  * @param msg   - sprava pre ktoru je vypocitavane sekvencne cislo
00680  * @return - Vrati sekvencne cislo danej spravy  
00681  */
00682 
00683 int ANSAQOS::SubQueue::calculateSn(cMessage *msg)
00684 {
00685   int sn;
00686   
00687   cPacket *pkt = dynamic_cast<cPacket *> (msg->dup());
00688   int len = pkt->getByteLength();
00689   
00690   short ipPrec = 0;
00691   if (dynamic_cast<IPDatagram *>(pkt))
00692   {
00693     IPDatagram *datagram = (IPDatagram *)pkt;
00694     ipPrec = (short) datagram->getDiffServCodePoint()/32;
00695   }
00696   
00697   delete pkt;
00698   
00699   sn = this->getLastSn() + ((32384 / (ipPrec + 1)) * len);
00700 
00701   return sn;
00702 }
00703 
00704 /*
00705  * substractSnFromAll(): 
00706  * Metoda, ktora odpocita zo vsetkych sekvencych cisel paketov danej fronty 
00707  * pozadovanu hodnotu. 
00708  * @param subNum        - hodnota, ktora bude zo sekvencnych cisel odcitana
00709  */
00710 
00711 void ANSAQOS::SubQueue::substractSnFromAll(int subNum)
00712 {
00713     if(!isQueueEmpty())
00714     {
00715         for (std::vector<SNPacket>::iterator it = snPackets.begin(); it!=snPackets.end(); ++it)
00716         {
00717             it->substractSn(subNum);
00718         }
00719         lastSn -= subNum;
00720     }
00721 }
00722 
00723 /*
00724  * setWeight(): 
00725  * Metoda, ktora vypocita na zaklade hodnoty IP precedence paketu vahu
00726  * danej podfronty. 
00727  * @param msg   - sprava, podla ktorej sa urci hodnota vyahy
00728  */
00729 
00730 void ANSAQOS::SubQueue::setWeight(cMessage *msg)
00731 {
00732   Flow flowID;
00733   flowID.parseFromMsg(msg);
00734   weight = 32384 / (flowID.ipPrec +1); // vypocet vahy pre podfrontu
00735 }
00736 
00737 /*
00738  * setVectorName(): 
00739  * Metoda, ktora inicializuje nazvy vektorov pre statistiku fronty
00740  * @param type  - typ fronty
00741  */
00742 
00743 void ANSAQOS::QueueConfig::setVectorName(ANSAQOS::QueueType type)
00744 {
00745   switch(type)
00746   {
00747     case ANSAQOS::Q_FIFO :
00748       qlenVec->setName("FIFO Length");
00749       dropVec->setName("FIFO Drops");
00750       break;
00751     case ANSAQOS::Q_WFQ : 
00752       qlenVec->setName("WFQ Length");
00753       dropVec->setName("WFQ Drops");
00754       break;
00755     case ANSAQOS::Q_PQ : 
00756       qlenVec->setName("PQ Length");
00757       dropVec->setName("PQ Drops");
00758       break;
00759     case ANSAQOS::Q_CQ : 
00760       qlenVec->setName("CQ Length");
00761       dropVec->setName("CQ Drops");
00762       break;
00763     default :
00764       break;
00765   } 
00766 }
00767 
00768 /*
00769  * Pretazenie operatoru "<<" pre vypis stavu fronty do grafickeho rozhrania 
00770  */
00771 
00772 std::ostream& operator<< (std::ostream& ostr, ANSAQOS::QueueConfig config)
00773 { 
00774   switch (config.getQueueType())
00775   {
00776     case ANSAQOS::Q_FIFO :
00777       ostr  << "Strategy: fifo;  Queue: ";
00778       ostr  << config.getCurrentHold() << "/";
00779       ostr  << config.getDroped() << "/";
00780       ostr  << config.getHoldCapacity() << " (size/dropped/max)";
00781       break;
00782     case ANSAQOS::Q_WFQ : 
00783       ostr  << "Strategy: weighted fair;  Queue: ";
00784       ostr  << config.getCurrentHold() << "/";
00785       ostr  << config.getHoldCapacity() << "/";
00786       ostr  << config.getCdt() << "/";
00787       ostr  << config.getDroped() << " (size/max total/threshold/drops); Conversations: ";
00788       ostr  << config.getNumQueues() << "/";
00789       ostr  << config.getMaxActQueues() << "/";
00790       ostr  << config.getMaxQueues() << " (active/max active/max total)";
00791       break;
00792     case ANSAQOS::Q_PQ : 
00793       ostr  << "Strategy: priority-list " << config.getListId();
00794       switch (config.getDefaultQueueId())
00795       {
00796         case 1 :
00797           ostr  << " (Default queue: High)";
00798           break;
00799         case 2 :
00800           ostr  << " (Default queue: Medium)";
00801           break;
00802         case 3 :
00803           ostr  << " (Default queue: Normal)";
00804           break;
00805         case 4 :
00806           ostr  << " (Default queue: Low)";
00807           break;
00808         default:
00809           ostr  << " (Default queue: Error)";
00810       }
00811       break;
00812     case ANSAQOS::Q_CQ : 
00813       ostr  << "Strategy: custom-list " << config.getListId();
00814       ostr  << " (Default queue: " << config.getDefaultQueueId() << ")";
00815       break;
00816     default :
00817       ostr  << "Error";
00818   }    
00819   
00820   return ostr;
00821 }
00822