cbr-module.cc

00001 //
00002 // Copyright (c) 2006 Regents of the SIGNET lab, University of Padova.
00003 // All rights reserved.
00004 //
00005 // Redistribution and use in source and binary forms, with or without
00006 // modification, are permitted provided that the following conditions
00007 // are met:
00008 // 1. Redistributions of source code must retain the above copyright
00009 //    notice, this list of conditions and the following disclaimer.
00010 // 2. Redistributions in binary form must reproduce the above copyright
00011 //    notice, this list of conditions and the following disclaimer in the
00012 //    documentation and/or other materials provided with the distribtion.
00013 // 3. Neither the name of the University of Padova (SIGNET lab) nor the 
00014 //    names of its contributors may be used to endorse or promote products 
00015 //    derived from this software without specific prior written permission.
00016 //
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
00018 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
00019 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
00020 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
00021 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00022 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00023 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
00024 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
00025 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
00026 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
00027 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028 //
00029 
00030 #include <iostream>
00031 
00032 #include <node-core.h>
00033 #include <ip.h>
00034 #include<rng.h>
00035 
00036 #include "cbr-module.h"
00037 
00038 
00039 extern packet_t PT_MCBR;
00040 
00041 int hdr_cbr::offset_;
00042 
00043 static class CbrPktClass : public PacketHeaderClass {
00044 public:
00045   CbrPktClass() : PacketHeaderClass("PacketHeader/CBR", sizeof(hdr_cbr)) {
00046     this->bind();
00047     bind_offset(&hdr_cbr::offset_);
00048   }
00049 } class_cbr_pkt; 
00050 
00051 
00052 
00053 static class CbrModuleClass : public TclClass {
00054 public:
00055   CbrModuleClass() : TclClass("Module/CBR") {}
00056   TclObject* create(int, const char*const*) {
00057     return (new CbrModule());
00058   }
00059 } class_module_cbr;
00060 
00061 
00062 
00063 void SendTimer::expire(Event *e)
00064 {
00065   module->transmit();
00066 }
00067 
00068 
00069 int CbrModule::uidcnt_;         // unique id of the packet generated
00070 
00071 
00072 CbrModule::CbrModule() 
00073   : sendTmr_(this),
00074     txsn(1),
00075     hrsn(0),
00076     pkts_recv(0),
00077     pkts_ooseq(0),
00078     pkts_lost(0),
00079     pkts_last_reset(0),
00080     rftt(-1),
00081     lrtime(0),
00082     sthr(0),
00083     sumrtt(0),
00084     rttsamples(0),
00085     sumftt(0),
00086     fttsamples(0),
00087     sumbytes(0),
00088     pob_(0),
00089     pob_time(0),
00090     pkts_opt(0),
00091     sumdt(0),
00092     MOS(0),
00093     first_pkt_rftt(-1),
00094     first_pkt_(-1),
00095   addfd_(-1)
00096 
00097 { // binding to TCL variables
00098   bind("period_", &period_);
00099   bind("destPort_", (int*)&dstPort_);
00100   bind("destAddr_", (int*)&dstAddr_);
00101   bind("packetSize_", &pktSize_);
00102   bind("alpha_", &alpha_);
00103   bind("PoissonTraffic_", &PoissonTraffic_);
00104   uidcnt_ = 0;
00105 }
00106 
00107 CbrModule::~CbrModule()
00108 {
00109 }
00110 
00111 // TCL command interpreter
00112 int CbrModule::command(int argc, const char*const* argv)
00113 {
00114   Tcl& tcl = Tcl::instance();
00115   if(argc==2)
00116     {
00117       if(strcasecmp(argv[1], "start") == 0)     // TCL command to start the packet generation and transmission
00118         {
00119           start();
00120           return TCL_OK;
00121         }
00122       else if(strcasecmp(argv[1], "stop") == 0) // TCL command to stop the packet generation
00123         {
00124           stop();
00125           return TCL_OK;
00126         }
00127       else if(strcasecmp(argv[1], "getrtt") == 0)       
00128         {
00129           tcl.resultf("%f",GetRTT());
00130           return TCL_OK;
00131         }
00132       else if(strcasecmp(argv[1], "getftt") == 0)       
00133         {
00134           tcl.resultf("%f",GetFTT());
00135           return TCL_OK;
00136         }
00137       else if(strcasecmp(argv[1], "getftt_pob") == 0)   
00138         {
00139           tcl.resultf("%f",GetFTTpob());
00140           return TCL_OK;
00141         }
00142       else if(strcasecmp(argv[1], "getper") == 0)       
00143         {
00144           tcl.resultf("%f",GetPER());
00145           return TCL_OK;
00146         }       
00147       else if(strcasecmp(argv[1], "getper_pb") == 0)    
00148         {
00149           tcl.resultf("%f",GetPER_PB());
00150           return TCL_OK;
00151         }       
00152 
00153       else if(strcasecmp(argv[1], "getthr") == 0)       
00154         {
00155           tcl.resultf("%f",GetTHR());
00156           return TCL_OK;
00157         }
00158       if(strcasecmp(argv[1], "getrttstd") == 0) 
00159         {
00160           tcl.resultf("%f",GetRTTstd());
00161           return TCL_OK;
00162         }
00163       
00164       if(strcasecmp(argv[1], "getfttstd") == 0) 
00165         {
00166           tcl.resultf("%f",GetFTTstd());
00167           return TCL_OK;
00168         }
00169        if(strcasecmp(argv[1], "getmos") == 0)   
00170         {
00171           tcl.resultf("%f",GetMOS());
00172           return TCL_OK;
00173         }
00174        if(strcasecmp(argv[1], "getsentpkts") == 0)      
00175         {
00176           tcl.resultf("%d",txsn-1);
00177           return TCL_OK;
00178         }
00179       if(strcasecmp(argv[1], "getrecvpkts") == 0)       
00180         {
00181           tcl.resultf("%d",pkts_recv);
00182           return TCL_OK;
00183         }
00184       else if(strcasecmp(argv[1], "sendPkt") == 0)      
00185         {
00186           sendPkt();
00187           return TCL_OK;
00188         }
00189       else if(strcasecmp(argv[1], "resetStats") == 0)   
00190         {
00191           resetStats();
00192           fprintf(stderr,"CbrModule::command() resetStats %s, pkts_last_reset=%d, hrsn=%d, txsn=%d\n", tag_ , pkts_last_reset, hrsn, txsn);
00193           return TCL_OK;
00194         }
00195     }
00196   if(argc==3){
00197         
00198     if(strcasecmp(argv[1], "use_playout_buffer") == 0)  // TCL command to start the packet generation and transmission
00199     {
00200       pob_ = 1;
00201       pob_time = atof(argv[2]);
00202       return TCL_OK;
00203     }
00204   
00205 if(strcasecmp(argv[1], "set_codec_rate") == 0)  // TCL command to start the packet generation and transmission
00206     {
00207       
00208     cr_ = atof(argv[2]);
00209       return TCL_OK;
00210     }
00211 
00212 if(strcasecmp(argv[1], "add_fixed_delay") == 0) // TCL command to start the packet generation and transmission
00213     {
00214       addfd_= 1;      
00215     fd_ = atof(argv[2]);
00216       return TCL_OK;
00217     }
00218 
00219 }
00220   return Module::command(argc, argv);
00221 }
00222 
00223 
00224 int CbrModule::crLayCommand(ClMessage* m)
00225 {
00226   switch (m->type()) 
00227     {
00228     
00229       //case whatever: 
00230       //    return 0;
00231       //    break;
00232     
00233     default:
00234       return Module::crLayCommand(m);    
00235     }  
00236 }
00237 
00238 void CbrModule::initPkt(Packet* p)
00239 {
00240   hdr_cmn* ch = hdr_cmn::access(p);
00241   ch->uid() = uidcnt_++;
00242   ch->ptype() = PT_MCBR;
00243   ch->size() = pktSize_;
00244   
00245   hdr_ip* iph = hdr_ip::access(p);
00246   iph->daddr() = dstAddr_;
00247   iph->dport() = dstPort_;
00248 
00249   hdr_cbr* cbrh = HDR_CBR(p);
00250   cbrh->sn = txsn;
00251   txsn++;
00252   cbrh->ts = Scheduler::instance().clock();
00253   ch->timestamp() = cbrh->ts;
00254 
00255   if (rftt >= 0)
00256     {
00257       cbrh->rftt = rftt;
00258       cbrh->rftt_valid = true;
00259     }
00260   else
00261     {
00262       cbrh->rftt_valid = false;
00263     }
00264 
00265 }
00266 
00267 void CbrModule::start()
00268 {
00269   sendTmr_.resched(getTimeBeforeNextPkt());
00270 }
00271 
00272 void CbrModule::sendPkt()
00273 {
00274   double delay = 0;
00275   Packet* p = Packet::alloc();
00276   initPkt(p);
00277   hdr_cmn* ch = hdr_cmn::access(p);
00278   if (debug_>10)
00279     printf("CbrModule(%d)::sendPkt, send a pkt (%d)\n",getId(), ch->uid());
00280   sendDown(p,delay);
00281 }
00282 
00283 void CbrModule::transmit()
00284 {
00285   sendPkt();
00286   // schedule next trasnmission
00287   sendTmr_.resched(getTimeBeforeNextPkt());
00288 }
00289 
00290 void CbrModule::stop()
00291 {
00292   sendTmr_.cancel();
00293 }
00294 
00295 
00296 void CbrModule::recv(Packet* p, Handler* h)
00297 {
00298         hdr_cmn* ch = hdr_cmn::access(p);
00299   
00300   recv(p);
00301 
00302 }
00303 
00304 
00305 void CbrModule::recv(Packet* p)
00306 {
00307   hdr_cmn* ch = hdr_cmn::access(p);
00308   if (debug_>10)     
00309     printf("CbrModule(%d)::recv(Packet*p,Handler*) pktId %d\n",getId(), ch->uid());
00310     
00311   if (ch->ptype() != PT_MCBR)
00312     {
00313       drop(p,1,CBR_DROP_REASON_UNKNOWN_TYPE);
00314       incrPktInvalid();
00315       return;
00316     }
00317 
00318   hdr_ip* iph = hdr_ip::access(p);
00319   if (iph->saddr() != dstAddr_)
00320     {
00321       drop(p,1,CBR_DROP_REASON_WRONG_SADDR);
00322       incrPktInvalid();
00323       return;
00324     }
00325   if (iph->sport() != dstPort_)
00326     {
00327       drop(p,1,CBR_DROP_REASON_WRONG_SPORT);
00328       incrPktInvalid();
00329       return;
00330     }
00331 
00332   hdr_cbr* cbrh = HDR_CBR(p);
00333 
00334   int esn = hrsn + 1; // expected sn
00335     
00336   if (cbrh->sn < esn)
00337     { // packet is out of sequence and is to be discarded
00338       incrPktOoseq();
00339       if (debug_ > 1)
00340         printf("CbrModule::recv() Pkt out of sequence! cbrh->sn=%d\thrsn=%d\tesn=%d\n",cbrh->sn,hrsn,esn);
00341       drop(p,1,CBR_DROP_REASON_OUT_OF_SEQUENCE);
00342       return;
00343     }
00344   
00345   rftt = Scheduler::instance().clock() - cbrh->ts;
00346 
00347 
00348   
00349   
00350  
00351 
00352 
00353   if(cbrh->rftt_valid) 
00354     {
00355     
00356       double rtt = rftt + cbrh->rftt;
00357       updateRTT(rtt);
00358     }
00359 
00360 
00361   if (addfd_){
00362     
00363     rftt += fd_;
00364   
00365   }
00366 
00367 
00368   updateFTT(rftt);
00369  
00370   
00371   if (pob_ )
00372     {
00373 
00374       if  (first_pkt_ <= 0){
00375         first_pkt_=1;
00376         first_pkt_rftt= rftt + pob_time;
00377 
00378 
00379       } else{
00380 
00381 
00382         if ( rftt  > first_pkt_rftt   ) {
00383 
00384           //if ( rftt  > GETFtt() + pob_time  ) {
00385 
00386           incrPktOutBuff();
00387 
00388           updateFTT(cbrh->rftt);
00389           drop(p,1,CBR_DROP_REASON_EXCEEDED_PLAYOUT);   
00390           return;}
00391       }
00392     }
00393   
00394   /* a new packet has been received */
00395   incrPktRecv();
00396   hrsn = cbrh->sn;  
00397   
00398   if (cbrh->sn > esn)
00399     { // packet losses are observed
00400       incrPktLost(cbrh->sn - (esn));     
00401     }
00402   
00403   
00404   /* throughput calculation */
00405 
00406 
00407  
00408 
00409 
00410 
00411 
00412   double dt = Scheduler::instance().clock() - lrtime;
00413   updateThroughput(ch->size(), dt);
00414   
00415  
00416   lrtime = Scheduler::instance().clock();
00417   
00418 
00419   /* Forward and Round Trip Time calculation */
00420   
00421    
00422 
00423   updateMOS(GetPER(), GetFTT(), cr_ );
00424 
00425 
00426   //drop(p,5,CBR_DROP_REASON_RECEIVED);   
00427   Packet::free(p);
00428 
00429   if (pkts_lost + pkts_recv + pkts_last_reset != hrsn)     
00430     fprintf(stderr,"ERROR CbrModule::recv() pkts_lost=%d  pkts_recv=%d  hrsn=%d\n", pkts_lost, pkts_recv, hrsn);
00431 
00432   //assert(pkts_lost + pkts_recv == hrsn);
00433   
00434 }
00435 
00436 
00437 
00438 double CbrModule::GetRTT() 
00439 {
00440   //return srtt;
00441   return (rttsamples>0) ? sumrtt/rttsamples : 0;
00442 }
00443 
00444 
00445 double CbrModule::GetFTT() 
00446 {
00447   //  return sftt;
00448   return (fttsamples>0) ? sumftt/fttsamples : 0;
00449 }
00450 
00451 
00452 double CbrModule::GetFTTpob() 
00453 {
00454   //  return sftt;
00455   if (pob_)
00456     return first_pkt_rftt;
00457   else 
00458     return (fttsamples>0) ? sumftt/fttsamples : 0;
00459 }
00460 
00461 
00462 
00463 double CbrModule::GetRTTstd() 
00464 {
00465   if (rttsamples>1) 
00466     {
00467       double var = (sumrtt2 - (sumrtt*sumrtt / rttsamples) ) / (rttsamples - 1);
00468       return (sqrt(var));
00469     }
00470   else 
00471     return 0;
00472 }
00473 
00474 
00475 double CbrModule::GetFTTstd() 
00476 {
00477   if (fttsamples>1) 
00478     {
00479       double var;
00480       var = (sumftt2 - (sumftt*sumftt / fttsamples) ) / (fttsamples - 1);
00481       if (var>0)
00482         return (sqrt(var));
00483       else return 0;
00484     }
00485   else 
00486     return 0;
00487 }
00488 
00489 
00490 double CbrModule::GetPER() 
00491 {
00492   if ((pkts_recv + pkts_lost)> 0)
00493     return ((double) pkts_lost / (double)(pkts_recv + pkts_lost));
00494   else 
00495     return 0;
00496 }
00497 
00498 
00499 double CbrModule::GetPER_PB() 
00500 {
00501   if ((pkts_recv  )> 0)
00502     return ((double) pkts_opt / (double)(pkts_recv+ pkts_lost));
00503   else 
00504     return 0;
00505 }
00506 
00507 double CbrModule::GetTHR() 
00508 {
00509   //  return sthr;
00510   return ((sumdt != 0) ? sumbytes*8/sumdt : 0);
00511 }
00512 
00513 double CbrModule::GetMOS() 
00514 {
00515   //  return sthr;
00516   return MOS;
00517 }
00518 
00519 
00520 void CbrModule::updateRTT(double rtt)
00521 {
00522   srtt = alpha_ * srtt + (1-alpha_) * rtt;
00523   sumrtt += rtt;
00524   sumrtt2 += rtt*rtt;
00525   rttsamples++;
00526 }
00527 
00528 void CbrModule::updateFTT(double ftt)
00529 {
00530   sftt = alpha_ * sftt + (1-alpha_) * ftt;
00531   
00532   sumftt += ftt;
00533   sumftt2 += ftt*ftt;
00534   fttsamples++;
00535 
00536 
00537 }
00538 
00539 
00540 void CbrModule::updateMOS(double Pdrop, double delay, double rsource){
00541   
00542   double mos_= getMOS(Pdrop, delay, rsource);
00543 
00544   MOS = alpha_ * MOS + (1-alpha_) * mos_;
00545   
00546 }
00547 
00548 
00549 
00550 double CbrModule::getMOS(double Pdrop, double delay, double rsource){
00551 
00552 
00553   
00554   double Iel;
00555   Iel = 34.3*log(1+12.8*Pdrop);
00556   
00557   
00558   double rl;
00559   rl = rsource; //suppongo che rsouce si a gia quantizzata ai avalori possibili
00560   
00561   
00562   double Iec_v [6];
00563   
00564  
00565   Iec_v[0]=(94.2);
00566   Iec_v[1]=(94.2-71);
00567   Iec_v[2]=(94.2-79);
00568   Iec_v[3]=(94.2-84);
00569   Iec_v[4]=(94.2-92);
00570   Iec_v[5]=(0);
00571   
00572   double  Iec_r [6];
00573   
00574  
00575   Iec_r[0]=(0);
00576   Iec_r[1]=(5.6);
00577   Iec_r[2]=(6.3);
00578   Iec_r[3]=(8);
00579   Iec_r[4]=(40);
00580   Iec_r[5]=(64);
00581   
00582   double Iec;
00583   
00584   if (rl>=Iec_r[5]){
00585     Iec= Iec_v[5];
00586   }else{
00587     
00588     for (int i=0;i<4; i++)
00589       {
00590         if (rl>=Iec_r[i] && rl<=Iec_r[i+1]) ;
00591         Iec= Iec_v[i] + (Iec_v[i+1] - Iec_v[i+1]) / (Iec_r[i+1] - Iec_r[i]) * rsource;
00592       }
00593   }
00594   
00595   
00596   
00597   double Id;
00598   Id = 24*delay +110*(delay-177.3e-3)*(delay>177.3e-3);
00599   double R;
00600   R = 94.2 - Id-Iec-Iel;
00601   double MOS_;
00602   
00603 
00604 
00605   if (R<100 && R > 0)
00606     MOS_ = max(1+0.035*R+7e-6*R*(R-60)*(100-R),1.0);
00607   if (R>=100)
00608     MOS_=4.5;
00609 
00610   if (R<=0)
00611     MOS_=1;
00612   // cerr << "MOS_  " <<  MOS <<endl;
00613   return MOS_;
00614 }
00615 
00616 
00617 
00618 
00619 
00620 
00621 
00622 
00623 void CbrModule::updateThroughput(int bytes, double dt)
00624 {
00625   //sthr = alpha_ * sthr + (1-alpha_) * thr;
00626 
00627   sumbytes += bytes;
00628   sumdt += dt;
00629 
00630   if (debug_) 
00631     cerr << "bytes=" << bytes << "  dt=" << dt << endl;
00632 }
00633 
00634 void CbrModule::incrPktLost(int npkts)
00635 {
00636   pkts_lost += npkts;
00637 }
00638 
00639 void CbrModule::incrPktRecv()
00640 {
00641   pkts_recv++;
00642 }
00643 
00644 void CbrModule::incrPktOoseq()
00645 {
00646   pkts_ooseq++;
00647 }
00648 
00649 void CbrModule::incrPktInvalid()
00650 {
00651   pkts_invalid++;
00652 }
00653 
00654 void CbrModule::incrPktOutBuff(){
00655   pkts_opt++; 
00656 }
00657 
00658 
00659 void CbrModule::resetStats()
00660 {
00661   pkts_last_reset += pkts_lost + pkts_recv;
00662   pkts_recv = 0;
00663   pkts_ooseq = 0;
00664   pkts_lost = 0;
00665   srtt = 0;
00666   sftt = 0;
00667   sthr = 0;
00668   //txsn = 1;
00669   //hrsn=0;
00670   rftt = -1;
00671   sumrtt = 0;
00672   sumrtt2 = 0;
00673   rttsamples = 0;
00674   sumftt = 0;
00675   sumftt2 = 0;
00676   fttsamples = 0;
00677   sumbytes = 0;
00678   sumdt = 0;            
00679   pob_time =0;          
00680   MOS=0;
00681 }
00682 
00683 
00684 double CbrModule::getTimeBeforeNextPkt()
00685 {
00686   if (period_<0)
00687     {
00688       fprintf(stderr,"%s : Error : period <= 0", __PRETTY_FUNCTION__);
00689       exit(1);
00690     }
00691   if (PoissonTraffic_)
00692     {
00693       double u = RNG::defaultrng()->uniform_double();
00694       double lambda = 1/period_;
00695       return (-log(u) / lambda);
00696     }
00697   else
00698     {
00699       // CBR
00700       return period_;
00701     }
00702   
00703   
00704 }

Generated on Wed Nov 26 15:47:27 2008 for NS-MIRACLE library by  doxygen 1.5.2