00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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_;
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 {
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
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)
00118 {
00119 start();
00120 return TCL_OK;
00121 }
00122 else if(strcasecmp(argv[1], "stop") == 0)
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)
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)
00206 {
00207
00208 cr_ = atof(argv[2]);
00209 return TCL_OK;
00210 }
00211
00212 if(strcasecmp(argv[1], "add_fixed_delay") == 0)
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
00230
00231
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
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;
00335
00336 if (cbrh->sn < esn)
00337 {
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
00385
00386 incrPktOutBuff();
00387
00388 updateFTT(cbrh->rftt);
00389 drop(p,1,CBR_DROP_REASON_EXCEEDED_PLAYOUT);
00390 return;}
00391 }
00392 }
00393
00394
00395 incrPktRecv();
00396 hrsn = cbrh->sn;
00397
00398 if (cbrh->sn > esn)
00399 {
00400 incrPktLost(cbrh->sn - (esn));
00401 }
00402
00403
00404
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
00420
00421
00422
00423 updateMOS(GetPER(), GetFTT(), cr_ );
00424
00425
00426
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
00433
00434 }
00435
00436
00437
00438 double CbrModule::GetRTT()
00439 {
00440
00441 return (rttsamples>0) ? sumrtt/rttsamples : 0;
00442 }
00443
00444
00445 double CbrModule::GetFTT()
00446 {
00447
00448 return (fttsamples>0) ? sumftt/fttsamples : 0;
00449 }
00450
00451
00452 double CbrModule::GetFTTpob()
00453 {
00454
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
00510 return ((sumdt != 0) ? sumbytes*8/sumdt : 0);
00511 }
00512
00513 double CbrModule::GetMOS()
00514 {
00515
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;
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
00613 return MOS_;
00614 }
00615
00616
00617
00618
00619
00620
00621
00622
00623 void CbrModule::updateThroughput(int bytes, double dt)
00624 {
00625
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
00669
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
00700 return period_;
00701 }
00702
00703
00704 }