├── README.md ├── mqecn.patch ├── queue ├── dwrr.cc ├── dwrr.h ├── wrr.cc └── wrr.h └── scripts ├── CDF_cache.tcl ├── CDF_dctcp.tcl ├── CDF_hadoop.tcl ├── CDF_vl2.tcl ├── result.py ├── run_simulation_diffserv.py ├── spine_empirical_diffserv.tcl ├── tcp-common-opt-raw.tcl ├── test-dwrr-2.tcl ├── test-dwrr.tcl ├── test-wrr-2.tcl └── test-wrr.tcl /README.md: -------------------------------------------------------------------------------- 1 | # MQ-ECN NS2 Simulation 2 | ## Software requirements 3 | To reproduce simulation results (Figure 9-13) of [MQ-ECN paper](http://www.cse.ust.hk/~kaichen/papers/mqecn-nsdi16.pdf), you need following softwares: 4 | - [Network Simulator (NS) 2.35](https://sourceforge.net/projects/nsnam/) 5 | - [mqecn.patch](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/mqecn.patch) (Modify TCP & Add ECMP) 6 | - [MQ-ECN code](https://github.com/HKUST-SING/MQ-ECN-NS2/tree/master/queue) (implement DWRR and WRR with different ECN marking schemes) 7 | - [Simulation scripts](https://github.com/HKUST-SING/MQ-ECN-NS2/tree/master/scripts) (run simulations in parallel and parse results) 8 | 9 | ## Installation 10 | Download [Network Simulator (NS) 2.35](https://sourceforge.net/projects/nsnam/) and unzip it. 11 | ``` 12 | $ tar -zxvf ns-allinone-2.35.tar.gz 13 | ``` 14 | 15 | Copy [mqecn.patch](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/mqecn.patch) to the *top ns-2.35 folder* (```ns-allinone-2.35```) and apply the patch. Then install NS2. 16 | ``` 17 | $ cd ns-allinone-2.35 18 | $ patch -p1 --ignore-whitespace -i mqecn.patch 19 | $ ./install 20 | ``` 21 | 22 | Copy files of [MQ-ECN code](https://github.com/HKUST-SING/MQ-ECN-NS2/tree/master/queue) to ```ns-allinone-2.35/ns-2.35/queue/``` 23 | 24 | Add ```queue/wrr.o queue/dwrr.o``` to ```ns-allinone-2.35/ns-2.35/Makefile``` 25 | 26 | Run ```make``` on ```/ns-allinone-2.35/ns-2.35``` 27 | 28 | ## Running Basic Simulations 29 | Before running large-scale simulations, you can run several small-scale simulations to understand the basic properties of MQ-ECN. The scripts for basic simulations are [test-wrr.tcl](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/test-wrr.tcl), [test-wrr-2.tcl](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/test-wrr-2.tcl), [test-dwrr.tcl](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/test-dwrr.tcl) and [test-dwrr-2.tcl](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/test-dwrr-2.tcl). The basic simulation scripts will generate three files: ```throughput.tr```, ```qlenfile.tr``` and ```tot_qlenfile.tr```. 30 | 31 | - The ```throughput.tr``` gives aggregate goodputs of different services. It has the following format: 32 | ``` 33 | Time, Goodput of Service 1, ..., Goodput of Service N 34 | ``` 35 | 36 | - The ```qlenfile.tr``` gives queue lengths (in bytes) of different service queues. It has the following format: 37 | ``` 38 | Time, Queue Length of Service Queue 1, ..., Queue Length of Service N 39 | ``` 40 | 41 | - The ```tot_qlenfile.tr``` gives the total queue length (in bytes) of the congested switch port. It has the following format: 42 | ``` 43 | Time, Queue Length of Switch Port 44 | ``` 45 | 46 | ## Running Large-Scale Simulations 47 | At the beginning, we briefly introduce the usage of each file in [scripts](https://github.com/HKUST-SING/MQ-ECN-NS2/tree/master/scripts) directory. 48 | - [CDF_cache.tcl](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/CDF_cache.tcl), [CDF_dctcp.tcl](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/CDF_dctcp.tcl), [CDF_hadoop.tcl](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/CDF_hadoop.tcl) and [CDF_vl2.tcl](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/CDF_vl2.tcl) give flow size distributions used in our paper. 49 | 50 | - [spine_empirical_diffserv.tcl](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/spine_empirical_diffserv.tcl) and [tcp-common-opt-raw.tcl] (https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/tcp-common-opt-raw.tcl) are NS2 TCL simulation scripts. 51 | 52 | - [run_simulation_diffserv.py](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/run_simulation_diffserv.py) is used to run NS2 simulations in parallel. 53 | 54 | - [result.py](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/result.py) is used to parse final results. 55 | 56 | Hence, to run simulations in parallel: 57 | ``` 58 | python run_simulation_diffserv.py 59 | ``` 60 | 61 | There are many parameters to configue in [run_simulation_diffserv.py](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/run_simulation_diffserv.py). Note that you need to modify ```ns_path``` and ```sim_script ``` correspondingly. By default, it runs 20x simulations in parallel and iterates over the per-queue ECN with the standard threshold, per-queue ECN with the minimum threshold and MQ-ECN. For each simulation, it will create a directory with the following name: 62 | ``` 63 | diffserv_[scheduler]_[transport]_scheme_[ECN scheme]_load_[network load]_service_[number of queues] 64 | ``` 65 | 66 | Each direcotry consists of two files: ```flow.tr``` and ```logFile.tr```. The ```flow.tr``` gives flow completion time results with the following format: 67 | ``` 68 | number of packets, flow completion time, number of timeouts, src ID, dst ID, service (queue) ID 69 | ``` 70 | 71 | You can use [result.py](https://github.com/HKUST-SING/MQ-ECN-NS2/blob/master/scripts/result.py) to parse ```flow.tr``` files as follows: 72 | ``` 73 | $ python result.py -a -i [directory_path]/flow.tr 74 | ``` 75 | 76 | ## Contact 77 | If you have any question about MQ-ECN simulation code, please contact [Wei Bai](http://sing.cse.ust.hk/~wei/). 78 | 79 | ## Acknowledgements 80 | We thank [Mohammad Alizadeh](https://people.csail.mit.edu/alizadeh/) for sharing pFabric simulation code and DCTCP patch. 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /mqecn.patch: -------------------------------------------------------------------------------- 1 | diff -Naur --no-dereference ns-allinone-2.35-raw/ns-2.35/classifier/classifier-mpath.cc ns-allinone-2.35/ns-2.35/classifier/classifier-mpath.cc 2 | --- ns-allinone-2.35-raw/ns-2.35/classifier/classifier-mpath.cc 2005-08-26 02:58:01.000000000 +0800 3 | +++ ns-allinone-2.35/ns-2.35/classifier/classifier-mpath.cc 2013-06-16 23:47:50.000000000 +0800 4 | @@ -1,4 +1,5 @@ 5 | -/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ 6 | +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t 7 | + -*- */ 8 | 9 | /* 10 | * Copyright (C) 1997 by the University of Southern California 11 | @@ -50,21 +51,106 @@ 12 | #endif 13 | 14 | #include "classifier.h" 15 | +#include "ip.h" 16 | 17 | class MultiPathForwarder : public Classifier { 18 | public: 19 | - MultiPathForwarder() : ns_(0) {} 20 | - virtual int classify(Packet*) { 21 | - int cl; 22 | + MultiPathForwarder() : ns_(0), nodeid_(0), nodetype_(0), perflow_(0), checkpathid_(0) { 23 | + bind("nodeid_", &nodeid_); 24 | + bind("nodetype_", &nodetype_); 25 | + bind("perflow_", &perflow_); 26 | + bind("checkpathid_", &checkpathid_); 27 | + } 28 | + virtual int classify(Packet* p) { 29 | + int cl; 30 | + hdr_ip* h = hdr_ip::access(p); 31 | + // Mohammad: multipath support 32 | + // fprintf(stdout, "perflow_ = %d, rcv packet in classifier\n", perflow_); 33 | + if (perflow_ || checkpathid_) { 34 | + /*if (h->flowid() >= 10000000) { 35 | + int fail = ns_; 36 | + do { 37 | + cl = ns_++; 38 | + ns_ %= (maxslot_ + 1); 39 | + } while (slot_[cl] == 0 && ns_ != fail); 40 | + return cl; 41 | + }*/ 42 | + 43 | + struct hkey { 44 | + int nodeid; 45 | + nsaddr_t src, dst; 46 | + int fid; 47 | + }; 48 | + struct hkey buf_; 49 | + buf_.nodeid = nodeid_; 50 | + buf_.src = mshift(h->saddr()); 51 | + buf_.dst = mshift(h->daddr()); 52 | + buf_.fid = h->flowid(); 53 | + /*if (checkpathid_) 54 | + buf_.prio = h->prio(); 55 | + else 56 | + buf_.prio = 0;*/ 57 | + char* bufString = (char*) &buf_; 58 | + int length = sizeof(hkey); 59 | + 60 | + unsigned int ms_ = (unsigned int) HashString(bufString, length); 61 | + if (checkpathid_) { 62 | + int pathNum = h->prio(); 63 | + int pathDig; 64 | + for (int i = 0; i < nodetype_; i++) { 65 | + pathDig = pathNum % 8; 66 | + pathNum /= 8; 67 | + } 68 | + //printf("%d: %d->%d\n", nodetype_, h->prio(), pathDig); 69 | + ms_ += h->prio(); //pathDig; 70 | + } 71 | + ms_ %= (maxslot_ + 1); 72 | + //printf("nodeid = %d, pri = %d, ms = %d\n", nodeid_, buf_.prio, ms_); 73 | + int fail = ms_; 74 | + do { 75 | + cl = ms_++; 76 | + ms_ %= (maxslot_ + 1); 77 | + } while (slot_[cl] == 0 && ms_ != fail); 78 | + //printf("nodeid = %d, pri = %d, cl = %d\n", nodeid_, h->prio(), cl); 79 | + } 80 | + 81 | + else { 82 | + //hdr_ip* h = hdr_ip::access(p); 83 | + //if (h->flowid() == 45) { 84 | + //cl = h->prio() % (maxslot_ + 1); 85 | + //} 86 | + //else { 87 | int fail = ns_; 88 | do { 89 | cl = ns_++; 90 | ns_ %= (maxslot_ + 1); 91 | } while (slot_[cl] == 0 && ns_ != fail); 92 | + } 93 | + //} 94 | + 95 | + 96 | return cl; 97 | } 98 | private: 99 | int ns_; 100 | + // Mohamamd: adding support for perflow multipath 101 | + int nodeid_; 102 | + int nodetype_; 103 | + int perflow_; 104 | + int checkpathid_; 105 | + 106 | + static unsigned int 107 | + HashString(register const char *bytes,int length) 108 | + { 109 | + register unsigned int result; 110 | + register int i; 111 | + 112 | + result = 0; 113 | + for (i = 0; i < length; i++) { 114 | + result += (result<<3) + *bytes++; 115 | + } 116 | + return result; 117 | + } 118 | }; 119 | 120 | static class MultiPathClass : public TclClass { 121 | diff -Naur --no-dereference ns-allinone-2.35-raw/ns-2.35/queue/red.cc ns-allinone-2.35/ns-2.35/queue/red.cc 122 | --- ns-allinone-2.35-raw/ns-2.35/queue/red.cc 2011-10-03 06:32:34.000000000 +0800 123 | +++ ns-allinone-2.35/ns-2.35/queue/red.cc 2016-02-14 21:13:54.712568705 +0800 124 | @@ -559,7 +559,7 @@ 125 | edv_.count_bytes = 0; 126 | hdr_flags* hf = hdr_flags::access(pickPacketForECN(pkt)); 127 | if (edp_.setbit && hf->ect() && 128 | - (!edp_.use_mark_p || edv_.v_prob1 < edp_.mark_p)) { 129 | + (!edp_.use_mark_p || edv_.v_prob1 <= edp_.mark_p)) { // For DCTCP: '<' is changed to '<=' here 130 | hf->ce() = 1; // mark Congestion Experienced bit 131 | // Tell the queue monitor here - call emark(pkt) 132 | return (0); // no drop 133 | diff -Naur --no-dereference ns-allinone-2.35-raw/ns-2.35/tcl/lib/ns-default.tcl ns-allinone-2.35/ns-2.35/tcl/lib/ns-default.tcl 134 | --- ns-allinone-2.35-raw/ns-2.35/tcl/lib/ns-default.tcl 2010-07-04 06:45:45.000000000 +0800 135 | +++ ns-allinone-2.35/ns-2.35/tcl/lib/ns-default.tcl 2016-02-14 21:13:54.716568758 +0800 136 | @@ -1026,6 +1026,10 @@ 137 | 138 | Agent/TCP set SetCWRonRetransmit_ true ; # added on 2005/06/19. 139 | # default changed on 2008/06/05. 140 | +# DCTCP 141 | +Agent/TCP set dctcp_ false; 142 | +Agent/TCP set dctcp_alpha_ 0.0; 143 | +Agent/TCP set dctcp_g_ 0.0625; 144 | 145 | # XXX Generate nam trace or plain old text trace for variables. 146 | # When it's true, generate nam trace. 147 | diff -Naur --no-dereference ns-allinone-2.35-raw/ns-2.35/tcp/tcp.cc ns-allinone-2.35/ns-2.35/tcp/tcp.cc 148 | --- ns-allinone-2.35-raw/ns-2.35/tcp/tcp.cc 2011-06-20 12:51:46.000000000 +0800 149 | +++ ns-allinone-2.35/ns-2.35/tcp/tcp.cc 2016-02-14 21:13:54.716568758 +0800 150 | @@ -101,6 +101,9 @@ 151 | bind("necnresponses_", &necnresponses_); 152 | bind("ncwndcuts_", &ncwndcuts_); 153 | bind("ncwndcuts1_", &ncwndcuts1_); 154 | + bind("dctcp_", &dctcp_); 155 | + bind("dctcp_alpha_", &dctcp_alpha_); 156 | + bind("dctcp_g_", &dctcp_g_); 157 | #endif /* TCP_DELAY_BIND_ALL */ 158 | 159 | } 160 | @@ -123,6 +126,11 @@ 161 | delay_bind_init_one("overhead_"); 162 | delay_bind_init_one("tcpTick_"); 163 | delay_bind_init_one("ecn_"); 164 | + // DCTCP 165 | + delay_bind_init_one("dctcp_"); 166 | + delay_bind_init_one("dctcp_alpha_"); 167 | + delay_bind_init_one("dctcp_g_"); 168 | + 169 | delay_bind_init_one("SetCWRonRetransmit_"); 170 | delay_bind_init_one("old_ecn_"); 171 | delay_bind_init_one("bugfix_ss_"); 172 | @@ -234,6 +242,10 @@ 173 | if (delay_bind(varName, localName, "overhead_", &overhead_, tracer)) return TCL_OK; 174 | if (delay_bind(varName, localName, "tcpTick_", &tcp_tick_, tracer)) return TCL_OK; 175 | if (delay_bind_bool(varName, localName, "ecn_", &ecn_, tracer)) return TCL_OK; 176 | + // Mohammad 177 | + if (delay_bind_bool(varName, localName, "dctcp_", &dctcp_, tracer)) return TCL_OK; 178 | + if (delay_bind(varName, localName, "dctcp_alpha_", &dctcp_alpha_ , tracer)) return TCL_OK; 179 | + if (delay_bind(varName, localName, "dctcp_g_", &dctcp_g_ , tracer)) return TCL_OK; 180 | if (delay_bind_bool(varName, localName, "SetCWRonRetransmit_", &SetCWRonRetransmit_, tracer)) return TCL_OK; 181 | if (delay_bind_bool(varName, localName, "old_ecn_", &old_ecn_ , tracer)) return TCL_OK; 182 | if (delay_bind_bool(varName, localName, "bugfix_ss_", &bugfix_ss_ , tracer)) return TCL_OK; 183 | @@ -1297,6 +1309,8 @@ 184 | } else { 185 | ssthresh_ = (int) decreasewin; 186 | } 187 | + else if (how & CLOSE_SSTHRESH_DCTCP) 188 | + ssthresh_ = (int) ((1 - dctcp_alpha_/2.0) * windowd()); 189 | else if (how & THREE_QUARTER_SSTHRESH) 190 | if (ssthresh_ < 3*cwnd_/4) 191 | ssthresh_ = (int)(3*cwnd_/4); 192 | @@ -1306,6 +1320,8 @@ 193 | if (first_decrease_ == 1 || slowstart || decrease_num_ == 0.5) { 194 | cwnd_ = halfwin; 195 | } else cwnd_ = decreasewin; 196 | + else if (how & CLOSE_CWND_DCTCP) 197 | + cwnd_ = (1 - dctcp_alpha_/2.0) * windowd(); 198 | else if (how & CWND_HALF_WITH_MIN) { 199 | // We have not thought about how non-standard TCPs, with 200 | // non-standard values of decrease_num_, should respond 201 | @@ -1328,7 +1344,9 @@ 202 | } 203 | if (ssthresh_ < 2) 204 | ssthresh_ = 2; 205 | - if (how & (CLOSE_CWND_HALF|CLOSE_CWND_RESTART|CLOSE_CWND_INIT|CLOSE_CWND_ONE)) 206 | + if (cwnd_ < 1) 207 | + cwnd_ = 1; 208 | + if (how & (CLOSE_CWND_HALF|CLOSE_CWND_RESTART|CLOSE_CWND_INIT|CLOSE_CWND_ONE|CLOSE_CWND_DCTCP)) 209 | cong_action_ = TRUE; 210 | 211 | fcnt_ = count_ = 0; 212 | @@ -1429,6 +1447,9 @@ 213 | rtt_backoff(); 214 | else ecn_backoff_ = 1; 215 | } else ecn_backoff_ = 0; 216 | + if (dctcp_) 217 | + slowdown(CLOSE_CWND_DCTCP|CLOSE_SSTHRESH_DCTCP); 218 | + else 219 | slowdown(CLOSE_CWND_HALF|CLOSE_SSTHRESH_HALF); 220 | ++necnresponses_ ; 221 | // added by sylvia to count number of ecn responses 222 | diff -Naur --no-dereference ns-allinone-2.35-raw/ns-2.35/tcp/tcp-full.cc ns-allinone-2.35/ns-2.35/tcp/tcp-full.cc 223 | --- ns-allinone-2.35-raw/ns-2.35/tcp/tcp-full.cc 2010-03-08 13:54:54.000000000 +0800 224 | +++ ns-allinone-2.35/ns-2.35/tcp/tcp-full.cc 2015-04-05 01:13:03.000000000 +0800 225 | @@ -229,6 +229,8 @@ 226 | if (delay_bind_bool(varName, localName, "ecn_syn_", &ecn_syn_, tracer)) return TCL_OK; 227 | if (delay_bind(varName, localName, "ecn_syn_wait_", &ecn_syn_wait_, tracer)) return TCL_OK; 228 | if (delay_bind_bool(varName, localName, "debug_", &debug_, tracer)) return TCL_OK; 229 | + if (delay_bind(varName, localName, "serviceid_", &serviceid_, tracer)) return TCL_OK; // Wei 230 | + if (delay_bind(varName, localName, "bytes_", &bytes_, tracer)) return TCL_OK; // Wei 231 | 232 | return TcpAgent::delay_bind_dispatch(varName, localName, tracer); 233 | } 234 | @@ -839,7 +841,8 @@ 235 | if (!p) p = allocpkt(); 236 | hdr_tcp *tcph = hdr_tcp::access(p); 237 | hdr_flags *fh = hdr_flags::access(p); 238 | - 239 | + hdr_ip* iph = hdr_ip::access(p); //Wei 240 | + 241 | /* build basic header w/options */ 242 | 243 | tcph->seqno() = seqno; 244 | @@ -871,6 +874,11 @@ 245 | /* Set ect() to 0. -M. Weigle 1/19/05 */ 246 | fh->ect() = 0; 247 | } 248 | + 249 | + // For DCTCP, ect should be set on all packets 250 | + if (dctcp_) 251 | + fh->ect() = ect_; 252 | + 253 | if (ecn_ && ect_ && recent_ce_ ) { 254 | // This is needed here for the ACK in a SYN, SYN/ACK, ACK 255 | // sequence. 256 | @@ -914,7 +922,12 @@ 257 | //printf("%f(%s)[state:%s]: sending pkt ", now(), name(), statestr(state_)); 258 | //prpkt(p); 259 | //} 260 | - 261 | + //Use IP header priority to denote service id 262 | + iph->prio()=serviceid_; 263 | + 264 | + //Update bytes sent 265 | + //bytes_+=datalen; 266 | + 267 | send(p, 0); 268 | 269 | return; 270 | @@ -960,9 +973,12 @@ 271 | // Q: how can this happen? 272 | 273 | if (maxseg_ == 0) 274 | - maxseg_ = size_ - headersize(); 275 | + maxseg_ = size_; // Mohammad: changed from size_ - headersize(); 276 | + /* Mohammad: This else condition is unnecessary and conflates 277 | + * with tcp.cc 278 | else 279 | size_ = maxseg_ + headersize(); 280 | + */ 281 | 282 | int is_retransmit = (seqno < maxseq_); 283 | int quiet = (highest_ack_ == maxseq_); 284 | @@ -1156,6 +1172,8 @@ 285 | */ 286 | flags_ &= ~(TF_ACKNOW|TF_DELACK); 287 | 288 | + delack_timer_.force_cancel(); 289 | + 290 | /* 291 | * if we have reacted to congestion recently, the 292 | * slowdown() procedure will have set cong_action_ and 293 | @@ -1178,6 +1196,8 @@ 294 | // and adjusted for SYNs and FINs which use up one number 295 | 296 | int highest = seqno + reliable; 297 | + if (highest > dctcp_maxseq) 298 | + dctcp_maxseq = highest; 299 | if (highest > maxseq_) { 300 | maxseq_ = highest; 301 | // 302 | @@ -1415,7 +1435,6 @@ 303 | { 304 | // we are now going to fast-retransmit and willtrace that event 305 | trace_event("FAST_RETX"); 306 | - 307 | recover_ = maxseq_; // recovery target 308 | last_cwnd_action_ = CWND_ACTION_DUPACK; 309 | return(foutput(seq, REASON_DUPACK)); // send one pkt 310 | @@ -1521,6 +1540,9 @@ 311 | int ackno = tcph->ackno(); // ack # from packet 312 | int tiflags = tcph->flags() ; // tcp flags from packet 313 | 314 | + //Added by Wei Bai 315 | + bytes_+=datalen; 316 | + 317 | //if (state_ != TCPS_ESTABLISHED || (tiflags&(TH_SYN|TH_FIN))) { 318 | //fprintf(stdout, "%f(%s)in state %s recv'd this packet: ", now(), name(), statestr(state_)); 319 | //prpkt(pkt); 320 | @@ -1564,11 +1586,19 @@ 321 | * at time t0 = (0.0 + k * interval_) for some k such 322 | * that t0 > now 323 | */ 324 | + /* 325 | + * Mohammad: commented this out for more efficient 326 | + * delayed ack generation. 327 | + * 328 | if (delack_interval_ > 0.0 && 329 | (delack_timer_.status() != TIMER_PENDING)) { 330 | int last = int(now() / delack_interval_); 331 | delack_timer_.resched(delack_interval_ * (last + 1.0) - now()); 332 | } 333 | + */ 334 | + 335 | + if (dctcp_) 336 | + update_dctcp_alpha(pkt); 337 | 338 | /* 339 | * Try header prediction: in seq data or in seq pure ACK 340 | @@ -1597,6 +1627,25 @@ 341 | // 342 | 343 | if (ecn_) { 344 | + if (dctcp_) { // DCTCP 345 | + if (fh->ce() && fh->ect()) { 346 | + // no CWR from peer yet... arrange to 347 | + // keep sending ECNECHO 348 | + if (recent_ce_ == FALSE) { 349 | + ce_transition = 1; 350 | + recent_ce_ = TRUE; 351 | + } else { 352 | + ce_transition = 0; 353 | + } 354 | + } else if (datalen > 0 && !fh->ce() && fh->ect()){ 355 | + if (recent_ce_ == TRUE) { 356 | + ce_transition = 1; 357 | + recent_ce_ = FALSE; 358 | + } else { 359 | + ce_transition = 0; 360 | + } 361 | + } 362 | + } else { 363 | if (fh->ce() && fh->ect()) { 364 | // no CWR from peer yet... arrange to 365 | // keep sending ECNECHO 366 | @@ -1607,6 +1656,7 @@ 367 | recent_ce_ = FALSE; 368 | } 369 | } 370 | + } 371 | 372 | // Header predication basically looks to see 373 | // if the incoming packet is an expected pure ACK 374 | @@ -1638,8 +1688,21 @@ 375 | // this routine scans all tcpcb's looking for 376 | // DELACK segments and when it finds them 377 | // changes DELACK to ACKNOW and calls tcp_output() 378 | + 379 | + /* DCTCP receiver state machine */ 380 | + if (dctcp_ && ce_transition && ((rcv_nxt_ - last_ack_sent_) > 0)) { 381 | + // Must send an immediate ACK with with previous ECN state 382 | + // before transitioning to new state 383 | + flags_ |= TF_ACKNOW; 384 | + recent_ce_ = !recent_ce_; 385 | + send_much(1, REASON_NORMAL, maxburst_); 386 | + recent_ce_ = !recent_ce_; 387 | + } 388 | + 389 | rcv_nxt_ += datalen; 390 | flags_ |= TF_DELACK; 391 | + // Mohammad 392 | + delack_timer_.resched(delack_interval_); 393 | recvBytes(datalen); // notify application of "delivery" 394 | // 395 | // special code here to simulate the operation 396 | @@ -1816,6 +1879,8 @@ 397 | */ 398 | if (datalen > 0) { 399 | flags_ |= TF_DELACK; // data there: wait 400 | + // Mohammad 401 | + delack_timer_.resched(delack_interval_); 402 | } else { 403 | flags_ |= TF_ACKNOW; // ACK peer's SYN 404 | } 405 | @@ -2131,10 +2196,31 @@ 406 | // cong_action bit 407 | // 408 | if (ecn_) { 409 | - if (fh->ce() && fh->ect()) 410 | + if (dctcp_) { // Mohammad 411 | + if (fh->ce() && fh->ect()) { 412 | + // no CWR from peer yet... arrange to 413 | + // keep sending ECNECHO 414 | + if (recent_ce_ == FALSE) { 415 | + ce_transition = 1; 416 | recent_ce_ = TRUE; 417 | - else if (fh->cwr()) 418 | + } else { 419 | + ce_transition = 0; 420 | + } 421 | + } else if (datalen > 0 && !fh->ce() && fh->ect()){ 422 | + if (recent_ce_ == TRUE) { 423 | + ce_transition = 1; 424 | recent_ce_ = FALSE; 425 | + } else { 426 | + ce_transition = 0; 427 | + } 428 | + } 429 | + } else { 430 | + if (fh->ce() && fh->ect()) { 431 | + recent_ce_ = TRUE; 432 | + } else if (fh->cwr()) { 433 | + recent_ce_ = FALSE; 434 | + } 435 | + } 436 | } 437 | 438 | // 439 | @@ -2297,11 +2383,19 @@ 440 | if ((!delay_growth_ || (rcv_nxt_ > 0)) && 441 | last_state_ == TCPS_ESTABLISHED) { 442 | if (!partial || open_cwnd_on_pack_) { 443 | - if (!ect_ || !hdr_flags::access(pkt)->ecnecho()) 444 | + if (!ect_ || !hdr_flags::access(pkt)->ecnecho() || ecn_burst_) 445 | opencwnd(); 446 | } 447 | } 448 | 449 | + // Mohammad: Detect bursts of ECN marks 450 | + if (ect_) { 451 | + if (!ecn_burst_ && hdr_flags::access(pkt)->ecnecho()) 452 | + ecn_burst_ = TRUE; 453 | + else if (ecn_burst_ && ! hdr_flags::access(pkt)->ecnecho()) 454 | + ecn_burst_ = FALSE; 455 | + } 456 | + 457 | if ((state_ >= TCPS_FIN_WAIT_1) && (ackno == maxseq_)) { 458 | ourfinisacked = TRUE; 459 | } 460 | @@ -2395,7 +2489,21 @@ 461 | // don't really have a process anyhow, just 462 | // accept the data here as-is (i.e. don't 463 | // require being in ESTABLISHED state) 464 | + 465 | + /* Mohammad: For DCTCP state machine */ 466 | + if (dctcp_ && ce_transition && ((rcv_nxt_ - last_ack_sent_) > 0)) { 467 | + // Must send an immediate ACK with with previous ECN state 468 | + // before transitioning to new state 469 | + flags_ |= TF_ACKNOW; 470 | + recent_ce_ = !recent_ce_; 471 | + send_much(1, REASON_NORMAL, maxburst_); 472 | + recent_ce_ = !recent_ce_; 473 | + } 474 | + 475 | flags_ |= TF_DELACK; 476 | + // Mohammad 477 | + delack_timer_.resched(delack_interval_); 478 | + 479 | rcv_nxt_ += datalen; 480 | tiflags = tcph->flags() & TH_FIN; 481 | 482 | @@ -2412,6 +2520,10 @@ 483 | // segments or hole-fills. Also, 484 | // send an ACK (or SACK) to the other side right now. 485 | // Note that we may have just a FIN here (datalen = 0) 486 | + 487 | + /* Note: The DCTCP receiver conveys the ECN-CE 488 | + received on each out-of-order data packet */ 489 | + 490 | int rcv_nxt_old_ = rcv_nxt_; // notify app. if changes 491 | tiflags = reass(pkt); 492 | if (rcv_nxt_ > rcv_nxt_old_) { 493 | @@ -2608,9 +2720,47 @@ 494 | } 495 | reset_rtx_timer(1); 496 | t_seqno_ = (highest_ack_ < 0) ? iss_ : int(highest_ack_); 497 | + dctcp_alpha_update_seq = t_seqno_; 498 | + dctcp_maxseq = dctcp_alpha_update_seq; 499 | fastrecov_ = FALSE; 500 | dupacks_ = 0; 501 | } 502 | + 503 | +/* 504 | + * Update dctcp alpha based on the ecn bit in the received packet. 505 | + * This procedure is called only when dctcp_ is 1. 506 | + */ 507 | +void FullTcpAgent::update_dctcp_alpha(Packet *pkt) 508 | +{ 509 | + int ecnbit = hdr_flags::access(pkt)->ecnecho(); 510 | + int ackno = hdr_tcp::access(pkt)->ackno(); 511 | + int acked_bytes = ackno - highest_ack_; 512 | + 513 | + if (acked_bytes <= 0) 514 | + acked_bytes = size_; 515 | + dctcp_total += acked_bytes; 516 | + if (ecnbit) { 517 | + dctcp_marked += acked_bytes; 518 | + } 519 | + 520 | + /* Check for barrier indicating its time to recalculate alpha. 521 | + * This code basically updated alpha roughly once per RTT. 522 | + */ 523 | + if (ackno > dctcp_alpha_update_seq) { 524 | + double temp_alpha; 525 | + dctcp_alpha_update_seq = dctcp_maxseq; 526 | + if (dctcp_total > 0) 527 | + temp_alpha = ((double) dctcp_marked) / dctcp_total; 528 | + else 529 | + temp_alpha = 0.0; 530 | + 531 | + dctcp_alpha_ = (1 - dctcp_g_) * dctcp_alpha_ + dctcp_g_ * temp_alpha; 532 | + dctcp_marked = 0; 533 | + dctcp_total = 0; 534 | + } 535 | +} 536 | + 537 | + 538 | /* 539 | * deal with timers going off. 540 | * 2 types for now: 541 | @@ -2662,7 +2812,8 @@ 542 | flags_ |= TF_ACKNOW; 543 | send_much(1, REASON_NORMAL, 0); 544 | } 545 | - delack_timer_.resched(delack_interval_); 546 | + // Mohammad 547 | + // delack_timer_.resched(delack_interval_); 548 | break; 549 | default: 550 | fprintf(stderr, "%f: FullTcpAgent(%s) Unknown Timeout type %d\n", 551 | @@ -2874,6 +3025,9 @@ 552 | * packet. -M. Weigle 6/19/02 553 | */ 554 | last_cwnd_action_ = CWND_ACTION_DUPACK; 555 | + /* Mohammad: cut window by half when we have 3 dup ack */ 556 | + if (dctcp_) 557 | + slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF); 558 | cancel_rtx_timer(); 559 | rtt_active_ = FALSE; 560 | int amt = fast_retransmit(highest_ack_); 561 | diff -Naur --no-dereference ns-allinone-2.35-raw/ns-2.35/tcp/tcp-full.h ns-allinone-2.35/ns-2.35/tcp/tcp-full.h 562 | --- ns-allinone-2.35-raw/ns-2.35/tcp/tcp-full.h 2008-10-15 01:42:52.000000000 +0800 563 | +++ ns-allinone-2.35/ns-2.35/tcp/tcp-full.h 2015-04-05 01:07:09.000000000 +0800 564 | @@ -120,7 +120,11 @@ 565 | last_send_time_(-1.0), infinite_send_(FALSE), irs_(-1), 566 | delack_timer_(this), flags_(0), 567 | state_(TCPS_CLOSED), recent_ce_(FALSE), 568 | - last_state_(TCPS_CLOSED), rq_(rcv_nxt_), last_ack_sent_(-1) { } 569 | + last_state_(TCPS_CLOSED), rq_(rcv_nxt_), last_ack_sent_(-1), 570 | + dctcp_total(0), dctcp_marked(0), dctcp_alpha_update_seq(0), 571 | + dctcp_maxseq(0), ce_transition(0), 572 | + bytes_(0),serviceid_(0)//Added by Wei Bai 573 | + { } 574 | 575 | ~FullTcpAgent() { cancel_timers(); rq_.clear(); } 576 | virtual void recv(Packet *pkt, Handler*); 577 | @@ -135,6 +139,9 @@ 578 | protected: 579 | virtual void delay_bind_init_all(); 580 | virtual int delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer); 581 | + 582 | + int bytes_; //Wei: bytes received 583 | + int serviceid_; //Wei: service id 584 | int closed_; 585 | int ts_option_size_; // header bytes in a ts option 586 | int pipe_; // estimate of pipe occupancy (for Sack) 587 | @@ -183,6 +190,8 @@ 588 | void finish(); 589 | void reset_rtx_timer(int); // adjust the rtx timer 590 | 591 | + void update_dctcp_alpha(Packet*); // DCTCP alpha update 592 | + 593 | virtual void timeout_action(); // what to do on rtx timeout 594 | virtual void dupack_action(); // what to do on dup acks 595 | virtual void pack_action(Packet*); // action on partial acks 596 | @@ -236,6 +245,16 @@ 597 | int last_state_; /* FSM state at last pkt recv */ 598 | int rcv_nxt_; /* next sequence number expected */ 599 | ReassemblyQueue rq_; /* TCP reassembly queue */ 600 | + 601 | + /* 602 | + * variables for DCTCP 603 | + */ 604 | + int dctcp_total; 605 | + int dctcp_marked; 606 | + int dctcp_alpha_update_seq; 607 | + int dctcp_maxseq; 608 | + int ce_transition; 609 | + 610 | /* 611 | * the following are part of a tcpcb in "real" RFC1323 TCP 612 | */ 613 | diff -Naur --no-dereference ns-allinone-2.35-raw/ns-2.35/tcp/tcp.h ns-allinone-2.35/ns-2.35/tcp/tcp.h 614 | --- ns-allinone-2.35-raw/ns-2.35/tcp/tcp.h 2011-08-27 03:29:57.000000000 +0800 615 | +++ ns-allinone-2.35/ns-2.35/tcp/tcp.h 2016-02-14 21:13:54.716568758 +0800 616 | @@ -104,7 +104,8 @@ 617 | #define CWND_HALF_WITH_MIN 0x00000200 618 | #define TCP_IDLE 0x00000400 619 | #define NO_OUTSTANDING_DATA 0x00000800 620 | - 621 | +#define CLOSE_SSTHRESH_DCTCP 0x00001000 622 | +#define CLOSE_CWND_DCTCP 0x00002000 623 | /* 624 | * tcp_tick_: 625 | * default 0.1, 626 | @@ -432,6 +433,12 @@ 627 | 628 | /* Used for ECN */ 629 | int ecn_; /* Explicit Congestion Notification */ 630 | + 631 | + /* Use for DCTCP */ 632 | + int dctcp_; 633 | + double dctcp_alpha_; 634 | + double dctcp_g_; 635 | + 636 | int cong_action_; /* Congestion Action. True to indicate 637 | that the sender responded to congestion. */ 638 | int ecn_burst_; /* True when the previous ACK packet 639 | -------------------------------------------------------------------------------- /queue/dwrr.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "flags.h" 7 | #include "dwrr.h" 8 | 9 | #define max(arg1,arg2) (arg1>arg2 ? arg1 : arg2) 10 | #define min(arg1,arg2) (arg1next)) 23 | { 24 | tmp->next = q; 25 | q->next = NULL; 26 | return; 27 | } 28 | /* Move to next node */ 29 | else 30 | { 31 | tmp = tmp->next; 32 | } 33 | } 34 | } 35 | } 36 | 37 | /* Remove and return the head node from the active list */ 38 | static PacketDWRR* RemoveHeadList(PacketDWRR* list) 39 | { 40 | if (list) 41 | { 42 | PacketDWRR* tmp = list->next; 43 | if (tmp) 44 | { 45 | list->next = tmp->next; 46 | return tmp; 47 | } 48 | /* This list is empty */ 49 | else 50 | { 51 | return NULL; 52 | } 53 | } 54 | else 55 | { 56 | return NULL; 57 | } 58 | } 59 | 60 | static class DWRRClass : public TclClass 61 | { 62 | public: 63 | DWRRClass() : TclClass("Queue/DWRR") {} 64 | TclObject* create(int argc, const char*const* argv) 65 | { 66 | return (new DWRR); 67 | } 68 | } class_dwrr; 69 | 70 | DWRR::DWRR() 71 | { 72 | queues = new PacketDWRR[MAX_QUEUE_NUM]; 73 | for (int i = 0; i < MAX_QUEUE_NUM; i++) 74 | queues[i].id = i; 75 | 76 | activeList = new PacketDWRR(); 77 | round_time = 0; 78 | last_idle_time = 0; 79 | 80 | total_qlen_tchan_ = NULL; 81 | qlen_tchan_ = NULL; 82 | 83 | queue_num_ = 8; 84 | mean_pktsize_ = 1500; //MTU 85 | port_thresh_ = 65; 86 | marking_scheme_ = PER_QUEUE_MARKING; 87 | estimate_round_alpha_ = 0.75; 88 | estimate_round_idle_interval_bytes_ = 1500; //MTU by default 89 | link_capacity_ = 10000000000; //10Gbps by default 90 | deque_marking_ = 0; //perform enqueue ECN/RED marking by default 91 | debug_ = 0; 92 | 93 | /* bind variables */ 94 | bind("queue_num_", &queue_num_); 95 | bind("mean_pktsize_", &mean_pktsize_); 96 | bind("port_thresh_", &port_thresh_); 97 | bind("marking_scheme_", &marking_scheme_); 98 | bind("estimate_round_alpha_", &estimate_round_alpha_); 99 | bind("estimate_round_idle_interval_bytes_", &estimate_round_idle_interval_bytes_); 100 | bind_bw("link_capacity_", &link_capacity_); 101 | bind_bool("deque_marking_", &deque_marking_); 102 | bind_bool("debug_", &debug_); 103 | } 104 | 105 | DWRR::~DWRR() 106 | { 107 | delete activeList; 108 | delete [] queues; 109 | } 110 | 111 | 112 | /* Get total length of all queues in bytes */ 113 | int DWRR::TotalByteLength() 114 | { 115 | int result = 0; 116 | 117 | for (int i = 0; i < queue_num_; i++) 118 | result+=queues[i].byteLength(); 119 | 120 | return result; 121 | } 122 | 123 | /* Determine whether a packet needs to get ECN marked. 124 | q is queue index of the packet. 125 | Return true if the packet should be marked */ 126 | bool DWRR::MarkingECN(int q) 127 | { 128 | if (q < 0 || q >= queue_num_) 129 | { 130 | fprintf(stderr, "illegal queue number\n"); 131 | return false; 132 | } 133 | 134 | /* Per-queue ECN marking */ 135 | if (marking_scheme_ == PER_QUEUE_MARKING) 136 | { 137 | if (queues[q].byteLength() > queues[q].thresh * mean_pktsize_) 138 | return true; 139 | else 140 | return false; 141 | } 142 | /* Per-port ECN marking */ 143 | else if (marking_scheme_ == PER_PORT_MARKING) 144 | { 145 | if (TotalByteLength() > port_thresh_ * mean_pktsize_) 146 | return true; 147 | else 148 | return false; 149 | } 150 | /* MQ-ECN */ 151 | else if (marking_scheme_ == MQ_MARKING) 152 | { 153 | double thresh = port_thresh_; 154 | if (round_time >= 0.000000001 && link_capacity_ > 0) 155 | thresh = min(queues[q].quantum * 8 / round_time / link_capacity_, 1) * port_thresh_; 156 | 157 | //For debug 158 | if(debug_) 159 | printf("round time: %.9f threshold of queue %d: %f\n", round_time, q, thresh); 160 | 161 | if (queues[q].byteLength() > thresh * mean_pktsize_) 162 | return true; 163 | else 164 | return false; 165 | } 166 | /* Unknown ECN marking scheme */ 167 | else 168 | { 169 | fprintf(stderr, "Unknown ECN marking scheme\n"); 170 | return false; 171 | } 172 | } 173 | 174 | /* 175 | * entry points from OTcL to set per queue state variables 176 | * - $q set-quantum queue_id queue_quantum (quantum is actually weight) 177 | * - $q set-thresh queue_id queue_thresh 178 | * - $q attach-total file 179 | * - $q attach-queue file 180 | * 181 | * NOTE: $q represents the discipline queue variable in OTcl. 182 | */ 183 | int DWRR::command(int argc, const char*const* argv) 184 | { 185 | if (argc == 3) 186 | { 187 | // attach a file to trace total queue length 188 | if (strcmp(argv[1], "attach-total") == 0) 189 | { 190 | int mode; 191 | const char* id = argv[2]; 192 | Tcl& tcl = Tcl::instance(); 193 | total_qlen_tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode); 194 | if (total_qlen_tchan_ == 0) 195 | { 196 | tcl.resultf("DWRR: trace: can't attach %s for writing", id); 197 | return (TCL_ERROR); 198 | } 199 | return (TCL_OK); 200 | } 201 | else if (strcmp(argv[1], "attach-queue") == 0) 202 | { 203 | int mode; 204 | const char* id = argv[2]; 205 | Tcl& tcl = Tcl::instance(); 206 | qlen_tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode); 207 | if (qlen_tchan_ == 0) 208 | { 209 | tcl.resultf("DWRR: trace: can't attach %s for writing", id); 210 | return (TCL_ERROR); 211 | } 212 | return (TCL_OK); 213 | } 214 | } 215 | else if (argc == 4) 216 | { 217 | if (strcmp(argv[1], "set-quantum")==0) 218 | { 219 | int queue_id = atoi(argv[2]); 220 | if (queue_id < queue_num_ && queue_id >= 0) 221 | { 222 | int quantum = atoi(argv[3]); 223 | if (quantum > 0) 224 | { 225 | queues[queue_id].quantum = quantum; 226 | return (TCL_OK); 227 | } 228 | else 229 | { 230 | fprintf(stderr,"illegal quantum value %s for queue %s\n", argv[3], argv[2]); 231 | exit(1); 232 | } 233 | } 234 | /* Exceed the maximum queue number or smaller than 0*/ 235 | else 236 | { 237 | fprintf(stderr,"no such queue %s\n",argv[2]); 238 | exit(1); 239 | } 240 | } 241 | else if (strcmp(argv[1], "set-thresh") == 0) 242 | { 243 | int queue_id = atoi(argv[2]); 244 | if (queue_id < queue_num_ && queue_id >= 0) 245 | { 246 | double thresh = atof(argv[3]); 247 | if (thresh >= 0) 248 | { 249 | queues[queue_id].thresh = thresh; 250 | return (TCL_OK); 251 | } 252 | else 253 | { 254 | fprintf(stderr,"illegal thresh value %s for queue %s\n", argv[3],argv[2]); 255 | exit(1); 256 | } 257 | } 258 | /* Exceed the maximum queue number or smaller than 0*/ 259 | else 260 | { 261 | fprintf(stderr,"no such queue %s\n",argv[2]); 262 | exit(1); 263 | } 264 | } 265 | } 266 | return (Queue::command(argc, argv)); 267 | } 268 | 269 | /* Receive a new packet */ 270 | void DWRR::enque(Packet *p) 271 | { 272 | hdr_ip *iph = hdr_ip::access(p); 273 | int prio = iph->prio(); 274 | hdr_flags* hf = hdr_flags::access(p); 275 | int pktSize = hdr_cmn::access(p)->size(); 276 | int qlimBytes = qlim_*mean_pktsize_; 277 | double now = Scheduler::instance().clock(); 278 | queue_num_ = max(min(queue_num_, MAX_QUEUE_NUM), 1); 279 | 280 | if (TotalByteLength() == 0) 281 | { 282 | double idle_interval = now - last_idle_time; 283 | int idle_slot_num = 0; 284 | 285 | /* Update round_time */ 286 | if (estimate_round_idle_interval_bytes_ > 0 && link_capacity_ > 0) 287 | { 288 | idle_slot_num = int(idle_interval / (estimate_round_idle_interval_bytes_ * 8 / link_capacity_)); 289 | round_time = round_time * pow(estimate_round_alpha_, idle_slot_num); 290 | } 291 | else 292 | { 293 | round_time = 0; 294 | } 295 | 296 | if (debug_ && marking_scheme_ == MQ_MARKING) 297 | printf("%.9f round time is reset to %.9f after %d idle time slots\n", now, round_time, idle_slot_num); 298 | } 299 | 300 | /* The shared buffer is overfilld */ 301 | if (TotalByteLength() + pktSize > qlimBytes) 302 | { 303 | drop(p); 304 | return; 305 | } 306 | 307 | if (prio >= queue_num_ || prio < 0) 308 | prio = queue_num_ - 1; 309 | 310 | queues[prio].enque(p); 311 | /* if queues[prio] is not in activeList */ 312 | if (queues[prio].active == false) 313 | { 314 | queues[prio].deficitCounter = 0; 315 | queues[prio].active = true; 316 | queues[prio].current = false; 317 | queues[prio].start_time = max(now, queues[prio].start_time); //Start time of this round 318 | InsertTailList(activeList, &queues[prio]); 319 | } 320 | /* Enqueue ECN marking */ 321 | if (deque_marking_ == 0 && MarkingECN(prio) && hf->ect()) 322 | hf->ce() = 1; 323 | } 324 | 325 | Packet *DWRR::deque(void) 326 | { 327 | PacketDWRR *headNode = NULL; 328 | Packet *pkt = NULL; 329 | hdr_flags* hf = NULL; 330 | int pktSize = 0; 331 | double round_time_sample = 0; 332 | double now = Scheduler::instance().clock(); 333 | 334 | /*At least one queue is active, activeList is not empty */ 335 | if (TotalByteLength() > 0) 336 | { 337 | /* We must go through all actives queues and select a packet to dequeue */ 338 | while (1) 339 | { 340 | headNode = activeList->next; //Get head node from activeList 341 | if (!headNode) 342 | fprintf (stderr,"no active flow\n"); 343 | 344 | /* if headNode is not empty */ 345 | if (headNode->length() > 0) 346 | { 347 | /* headNode has not been served yet in this round */ 348 | if (headNode->current == false) 349 | { 350 | headNode->deficitCounter += headNode->quantum; 351 | headNode->current = true; 352 | } 353 | 354 | pktSize = hdr_cmn::access(headNode->head())->size(); 355 | /* if we have enough quantum to dequeue the head packet */ 356 | if (pktSize <= headNode->deficitCounter) 357 | { 358 | pkt = headNode->deque(); 359 | headNode->deficitCounter -= pktSize; 360 | hf = hdr_flags::access(pkt); 361 | /* Dequeue ECN marking */ 362 | if (deque_marking_ > 0 && MarkingECN(headNode->id) > 0 && hf->ect()) 363 | hf->ce() = 1; 364 | 365 | /* After dequeue, headNode becomes empty. In such case, we should delete this queue from activeList. */ 366 | if (headNode->length() == 0) 367 | { 368 | round_time_sample = now + pktSize * 8 / link_capacity_ - headNode->start_time ; 369 | round_time = round_time * estimate_round_alpha_ + round_time_sample * (1 - estimate_round_alpha_); 370 | 371 | if (debug_ && marking_scheme_ == MQ_MARKING) 372 | printf("%.9f queue: %d sample round time: %.9f round time: %.9f\n", now, headNode->id, round_time_sample, round_time); 373 | 374 | headNode = RemoveHeadList(activeList); 375 | headNode->start_time = now + pktSize * 8 / link_capacity_; 376 | headNode->deficitCounter = 0; 377 | headNode->active = false; 378 | headNode->current = false; 379 | } 380 | break; 381 | } 382 | /* If we don't have enough quantum to dequeue the head packet and the queue is not empty */ 383 | else 384 | { 385 | headNode = RemoveHeadList(activeList); 386 | headNode->current = false; 387 | round_time_sample = now - headNode->start_time; 388 | round_time = round_time * estimate_round_alpha_ + round_time_sample * (1-estimate_round_alpha_); 389 | 390 | if (debug_ && marking_scheme_ == MQ_MARKING) 391 | printf("%.9f queue: %d sample round time: %.9f round time: %.9f\n", now, headNode->id, round_time_sample, round_time); 392 | 393 | headNode->start_time = now; //Reset start time 394 | InsertTailList(activeList, headNode); 395 | } 396 | } 397 | } 398 | } 399 | 400 | if (TotalByteLength() == 0) 401 | last_idle_time = now; 402 | 403 | trace_qlen(); 404 | trace_total_qlen(); 405 | 406 | return pkt; 407 | } 408 | 409 | /* routine to write total qlen records */ 410 | void DWRR::trace_total_qlen() 411 | { 412 | if (total_qlen_tchan_) 413 | { 414 | char wrk[500] = {0}; 415 | int n; 416 | double t = Scheduler::instance().clock(); 417 | sprintf(wrk, "%g, %d", t,TotalByteLength()); 418 | n = strlen(wrk); 419 | wrk[n] = '\n'; 420 | wrk[n+1] = 0; 421 | (void)Tcl_Write(total_qlen_tchan_, wrk, n+1); 422 | } 423 | } 424 | 425 | /* routine to write per-queue qlen records */ 426 | void DWRR::trace_qlen() 427 | { 428 | if (qlen_tchan_) 429 | { 430 | char wrk[500] = {0}; 431 | int n; 432 | double t = Scheduler::instance().clock(); 433 | sprintf(wrk, "%g", t); 434 | n = strlen(wrk); 435 | wrk[n] = 0; 436 | (void)Tcl_Write(qlen_tchan_, wrk, n); 437 | 438 | for (int i = 0; i < queue_num_; i++) 439 | { 440 | sprintf(wrk, ", %d",queues[i].byteLength()); 441 | n = strlen(wrk); 442 | wrk[n] = 0; 443 | (void)Tcl_Write(qlen_tchan_, wrk, n); 444 | } 445 | (void)Tcl_Write(qlen_tchan_, "\n", 1); 446 | } 447 | } 448 | -------------------------------------------------------------------------------- /queue/dwrr.h: -------------------------------------------------------------------------------- 1 | #ifndef ns_dwrr_h 2 | #define ns_dwrr_h 3 | 4 | #include "queue.h" 5 | #include "config.h" 6 | #include "trace.h" 7 | 8 | /*Maximum queue number */ 9 | #define MAX_QUEUE_NUM 64 10 | 11 | /* Per-queue ECN marking */ 12 | #define PER_QUEUE_MARKING 0 13 | /* Per-port ECN marking */ 14 | #define PER_PORT_MARKING 1 15 | /* MQ-ECN */ 16 | #define MQ_MARKING 2 17 | 18 | class PacketDWRR; 19 | class DWRR; 20 | 21 | class PacketDWRR: public PacketQueue 22 | { 23 | public: 24 | PacketDWRR(): quantum(1500), deficitCounter(0), thresh(0), active(false), current(false), start_time(0), next(NULL) {} 25 | 26 | int id; //queue ID 27 | int quantum; //quantum (weight) of this queue 28 | int deficitCounter; //deficit counter for this queue 29 | double thresh; //per-queue ECN marking threshold (pkts) 30 | bool active; //whether this queue is active (qlen>0) 31 | bool current; //whether this queue is currently being served (deficitCounter has been updated for thie round) 32 | double start_time; //time when this queue is inserted to active list 33 | PacketDWRR *next; //pointer to next node 34 | 35 | friend class DWRR; 36 | }; 37 | 38 | class DWRR : public Queue 39 | { 40 | public: 41 | DWRR(); 42 | ~DWRR(); 43 | virtual int command(int argc, const char*const* argv); 44 | 45 | protected: 46 | Packet *deque(void); 47 | void enque(Packet *pkt); 48 | 49 | int TotalByteLength(); //Get total length of all queues in bytes 50 | bool MarkingECN(int q); //Determine whether we need to mark ECN, q is queue index 51 | void trace_total_qlen(); //routine to write total qlen records 52 | void trace_qlen(); //routine to write per-queue qlen records 53 | 54 | /* Variables */ 55 | PacketDWRR *queues; //underlying multi-FIFO (CoS) queues 56 | PacketDWRR *activeList; //list for active queues 57 | double round_time; //estimation value for round time 58 | double last_idle_time; //Last time when link becomes idle 59 | 60 | Tcl_Channel total_qlen_tchan_; //place to write total_qlen records 61 | Tcl_Channel qlen_tchan_; //place to write per-queue qlen records 62 | 63 | int queue_num_; //number of queues 64 | int mean_pktsize_; //MTU in bytes 65 | double port_thresh_; //per-port ECN marking threshold (pkts) 66 | int marking_scheme_; //ECN marking policy 67 | double estimate_round_alpha_; //factor between 0 and 1 for round time estimation 68 | int estimate_round_idle_interval_bytes_; //Time interval (divided by link capacity) to update round time when link is idle. 69 | double link_capacity_; //Link capacity 70 | int deque_marking_; //shall we enable dequeue ECN/RED marking 71 | int debug_; //debug more(true) or not(false) 72 | }; 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /queue/wrr.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "flags.h" 6 | #include "wrr.h" 7 | 8 | #define max(arg1,arg2) (arg1>arg2 ? arg1 : arg2) 9 | #define min(arg1,arg2) (arg1= queue_num_) 75 | { 76 | fprintf(stderr, "illegal queue index\n"); 77 | return false; 78 | } 79 | 80 | /* Per-queue ECN marking */ 81 | if (marking_scheme_ == PER_QUEUE_MARKING) 82 | { 83 | if (queues[q].byteLength() > queues[q].thresh * mean_pktsize_) 84 | return true; 85 | else 86 | return false; 87 | } 88 | /* Per-port ECN marking */ 89 | else if (marking_scheme_ == PER_PORT_MARKING) 90 | { 91 | if (TotalByteLength() > port_thresh_ * mean_pktsize_) 92 | return true; 93 | else 94 | return false; 95 | } 96 | /* MQ-ECN*/ 97 | else if (marking_scheme_ == MQ_MARKING) 98 | { 99 | double thresh = port_thresh_; 100 | if (round_time >= 0.000000001 && link_capacity_ > 0) 101 | thresh = min(queues[q].quantum * 8 / round_time / link_capacity_, 1) * port_thresh_; 102 | 103 | //For debug 104 | if(debug_) 105 | printf("round time: %.9f threshold of queue %d: %f\n", round_time, q, thresh); 106 | 107 | if (queues[q].byteLength() > thresh * mean_pktsize_) 108 | return true; 109 | else 110 | return false; 111 | } 112 | /* Unknown ECN marking scheme */ 113 | else 114 | { 115 | fprintf(stderr, "Unknown ECN marking scheme\n"); 116 | return false; 117 | } 118 | } 119 | 120 | /* 121 | * entry points from OTcL to set per queue state variables 122 | * - $q set-quantum queue_id queue_quantum (quantum is actually weight in WRR) 123 | * - $q set-thresh queue_id queue_thresh 124 | * - $q attach-total file 125 | * - $q attach-queue file 126 | * 127 | * NOTE: $q represents the discipline queue variable in OTcl. 128 | */ 129 | int WRR::command(int argc, const char*const* argv) 130 | { 131 | if (argc == 3) 132 | { 133 | //attach a file to trace total queue length 134 | if (strcmp(argv[1], "attach-total") == 0) 135 | { 136 | int mode; 137 | const char* id = argv[2]; 138 | Tcl& tcl = Tcl::instance(); 139 | total_qlen_tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode); 140 | if (total_qlen_tchan_ == 0) 141 | { 142 | tcl.resultf("WRR: trace: can't attach %s for writing", id); 143 | return (TCL_ERROR); 144 | } 145 | return (TCL_OK); 146 | } 147 | else if (strcmp(argv[1], "attach-queue") == 0) 148 | { 149 | int mode; 150 | const char* id = argv[2]; 151 | Tcl& tcl = Tcl::instance(); 152 | qlen_tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode); 153 | if (qlen_tchan_ == 0) 154 | { 155 | tcl.resultf("WRR: trace: can't attach %s for writing", id); 156 | return (TCL_ERROR); 157 | } 158 | return (TCL_OK); 159 | } 160 | } 161 | else if (argc == 4) 162 | { 163 | if (strcmp(argv[1], "set-quantum")==0) 164 | { 165 | int queue_id = atoi(argv[2]); 166 | if (queue_id < queue_num_ && queue_id >= 0) 167 | { 168 | int quantum = atoi(argv[3]); 169 | if (quantum > 0) 170 | { 171 | queues[queue_id].quantum = quantum; 172 | return TCL_OK; 173 | } 174 | else 175 | { 176 | fprintf(stderr, "illegal quantum value %s for queue %s\n", argv[3], argv[2]); 177 | exit(1); 178 | } 179 | } 180 | /* Exceed the maximum queue number or smaller than 0*/ 181 | else 182 | { 183 | fprintf(stderr,"no such queue %s\n", argv[2]); 184 | exit(1); 185 | } 186 | } 187 | else if (strcmp(argv[1], "set-thresh") == 0) 188 | { 189 | int queue_id = atoi(argv[2]); 190 | if (queue_id < queue_num_ && queue_id >= 0) 191 | { 192 | double thresh = atof(argv[3]); 193 | if (thresh >= 0) 194 | { 195 | queues[queue_id].thresh = thresh; 196 | return (TCL_OK); 197 | } 198 | else 199 | { 200 | fprintf(stderr, "illegal thresh value %s for queue %s\n", argv[3], argv[2]); 201 | exit(1); 202 | } 203 | } 204 | /* Exceed the maximum queue number or smaller than 0*/ 205 | else 206 | { 207 | fprintf(stderr,"no such queue %s\n", argv[2]); 208 | exit(1); 209 | } 210 | } 211 | } 212 | return (Queue::command(argc, argv)); 213 | } 214 | 215 | /* Receive a new packet */ 216 | void WRR::enque(Packet *p) 217 | { 218 | hdr_ip *iph = hdr_ip::access(p); 219 | int prio = iph->prio(); 220 | hdr_flags* hf = hdr_flags::access(p); 221 | int pktSize = hdr_cmn::access(p)->size(); 222 | int qlimBytes = qlim_*mean_pktsize_; 223 | double now = Scheduler::instance().clock(); 224 | queue_num_ = max(min(queue_num_, MAX_QUEUE_NUM), 1); 225 | 226 | if (TotalByteLength() == 0) 227 | { 228 | double idle_interval = now - last_idle_time; 229 | int idle_slot_num = 0; 230 | 231 | /* Update round_time */ 232 | if (estimate_round_idle_interval_bytes_ > 0 && link_capacity_ > 0) 233 | { 234 | idle_slot_num = int(idle_interval / (estimate_round_idle_interval_bytes_ * 8 / link_capacity_)); 235 | round_time = round_time * pow(estimate_round_alpha_, idle_slot_num); 236 | } 237 | else 238 | { 239 | round_time = 0; 240 | } 241 | 242 | if (debug_ && marking_scheme_ == MQ_MARKING) 243 | printf("%.9f round time is reset to %.9f after %d idle time slots\n", now, round_time, idle_slot_num); 244 | } 245 | 246 | /* The shared buffer is overfilld */ 247 | if (TotalByteLength() + pktSize > qlimBytes) 248 | { 249 | drop(p); 250 | return; 251 | } 252 | 253 | if (prio >= queue_num_ || prio < 0) 254 | prio = queue_num_ - 1; 255 | 256 | /* Reset start time of current queue if it is empty */ 257 | if (queues[prio].length() == 0) 258 | queues[prio].start_time = max(now, queues[prio].start_time); 259 | 260 | queues[prio].enque(p); 261 | /* Enqueue ECN marking */ 262 | if (deque_marking_ == 0 && MarkingECN(prio) > 0 && hf->ect()) 263 | hf->ce() = 1; 264 | } 265 | 266 | Packet *WRR::deque(void) 267 | { 268 | Packet *pkt = NULL; 269 | hdr_flags* hf = NULL; 270 | int pktSize = 0; 271 | double round_time_sample = 0; 272 | double now = Scheduler::instance().clock(); 273 | 274 | /*At least one queue is active*/ 275 | if (TotalByteLength() > 0) 276 | { 277 | while (1) 278 | { 279 | /* If current queue is active */ 280 | if (queues[current].length() > 0) 281 | { 282 | if (queues[current].counter_updated == false) 283 | { 284 | queues[current].counter_updated = true; 285 | queues[current].counter = queues[current].quantum; 286 | } 287 | 288 | pkt = queues[current].head(); 289 | pktSize = hdr_cmn::access(pkt)->size(); 290 | 291 | /* We have enough quantum to dequeue this packet */ 292 | if (pktSize <= queues[current].counter) 293 | { 294 | hf = hdr_flags::access(pkt); 295 | /* Dequeue ECN marking */ 296 | if (deque_marking_ > 0 && MarkingECN(current) > 0 && hf->ect()) 297 | hf->ce() = 1; 298 | 299 | pkt = queues[current].deque(); 300 | queues[current].counter -= pktSize; 301 | 302 | /* After dequeue, current queue becomes empty */ 303 | if (queues[current].length() == 0) 304 | { 305 | round_time_sample = now + pktSize * 8 / link_capacity_ - queues[current].start_time; 306 | round_time = round_time * estimate_round_alpha_ + round_time_sample * (1 - estimate_round_alpha_); 307 | if (debug_ && marking_scheme_ == MQ_MARKING) 308 | printf("sample round time: %.9f round time: %.9f\n", round_time_sample, round_time); 309 | 310 | /* Reset start time of current queue & Move to next queue */ 311 | queues[current].start_time = now + pktSize * 8 / link_capacity_; 312 | queues[current].counter_updated = false; 313 | current = (current + 1) % queue_num_; 314 | } 315 | 316 | break; 317 | } 318 | /* No enough quantum to dequeue this packet */ 319 | else 320 | { 321 | round_time_sample = now - queues[current].start_time; 322 | round_time = round_time * estimate_round_alpha_ + round_time_sample * (1 - estimate_round_alpha_); 323 | if (debug_ && marking_scheme_ == MQ_MARKING) 324 | printf("sample round time: %.9f round time: %.9f\n", round_time_sample, round_time); 325 | 326 | queues[current].start_time = now; 327 | queues[current].counter_updated = false; 328 | current = (current + 1) % queue_num_; 329 | } 330 | } 331 | /* Empty queue! No need to take any sample. */ 332 | else 333 | { 334 | queues[current].start_time = now; 335 | queues[current].counter_updated = false; 336 | current = (current + 1) % queue_num_; 337 | } 338 | } 339 | } 340 | 341 | if (TotalByteLength() == 0) 342 | last_idle_time = now; 343 | 344 | trace_total_qlen(); 345 | trace_qlen(); 346 | 347 | return pkt; 348 | } 349 | 350 | /* routine to write total qlen records */ 351 | void WRR::trace_total_qlen() 352 | { 353 | if (total_qlen_tchan_) 354 | { 355 | char wrk[500] = {0}; 356 | int n; 357 | double t = Scheduler::instance().clock(); 358 | sprintf(wrk, "%g, %d", t,TotalByteLength()); 359 | n = strlen(wrk); 360 | wrk[n] = '\n'; 361 | wrk[n+1] = 0; 362 | (void)Tcl_Write(total_qlen_tchan_, wrk, n+1); 363 | } 364 | } 365 | 366 | /* routine to write per-queue qlen records */ 367 | void WRR::trace_qlen() 368 | { 369 | if (qlen_tchan_) 370 | { 371 | char wrk[500] = {0}; 372 | int n; 373 | double t = Scheduler::instance().clock(); 374 | sprintf(wrk, "%g", t); 375 | n = strlen(wrk); 376 | wrk[n] = 0; 377 | (void)Tcl_Write(qlen_tchan_, wrk, n); 378 | 379 | for (int i = 0; i < queue_num_; i++) 380 | { 381 | sprintf(wrk, ", %d", queues[i].byteLength()); 382 | n = strlen(wrk); 383 | wrk[n] = 0; 384 | (void)Tcl_Write(qlen_tchan_, wrk, n); 385 | } 386 | (void)Tcl_Write(qlen_tchan_, "\n", 1); 387 | } 388 | } 389 | -------------------------------------------------------------------------------- /queue/wrr.h: -------------------------------------------------------------------------------- 1 | #ifndef ns_wrr_h 2 | #define ns_wrr_h 3 | 4 | #include "queue.h" 5 | #include "config.h" 6 | #include "trace.h" 7 | 8 | /*Maximum queue number */ 9 | #define MAX_QUEUE_NUM 64 10 | 11 | /* Per-queue ECN marking */ 12 | #define PER_QUEUE_MARKING 0 13 | /* Per-port ECN marking */ 14 | #define PER_PORT_MARKING 1 15 | /* MQ-ECN */ 16 | #define MQ_MARKING 2 17 | 18 | class PacketWRR; 19 | class WRR; 20 | 21 | class PacketWRR: public PacketQueue 22 | { 23 | public: 24 | PacketWRR(): quantum(1500), counter(0), thresh(65), start_time(0), counter_updated(false) {} 25 | 26 | int quantum; //quantum of this queue 27 | int counter; //counter for bytes that can be sent in this round 28 | double thresh; //per-queue ECN marking threshold (pkts) 29 | double start_time; //time when the queue waits for scheduling in this round 30 | bool counter_updated; //whether the counter has been updated in this round 31 | 32 | friend class WRR; 33 | }; 34 | 35 | class WRR : public Queue 36 | { 37 | public: 38 | WRR(); 39 | ~WRR(); 40 | virtual int command(int argc, const char*const* argv); 41 | 42 | protected: 43 | Packet *deque(void); 44 | void enque(Packet *pkt); 45 | 46 | int TotalByteLength(); //Get total length of all queues in bytes 47 | bool MarkingECN(int q); //Determine whether we need to mark ECN, q is queue index 48 | void trace_total_qlen(); //routine to write total qlen records 49 | void trace_qlen(); //routine to write per-queue qlen records 50 | 51 | /* Variables */ 52 | PacketWRR *queues; //underlying multi-FIFO (CoS) queues 53 | double round_time; //Smooth estimation value of round time 54 | double last_idle_time; //Last time when link becomes idle 55 | int current; //current queue index 56 | 57 | Tcl_Channel total_qlen_tchan_; //place to write total_qlen records 58 | Tcl_Channel qlen_tchan_; //place to write per-queue qlen records 59 | 60 | int queue_num_; //the total number of queues 61 | int mean_pktsize_; //MTU in bytes 62 | double port_thresh_; //per-port ECN marking threshold (pkts) 63 | int marking_scheme_; //ECN marking policy 64 | double estimate_round_alpha_; //factor between 0 and 1 for round time estimation 65 | int estimate_round_idle_interval_bytes_; //Time interval (divided by link capacity) to update round time when link is idle 66 | double link_capacity_; //Link capacity 67 | int deque_marking_; //shall we enable dequeue ECN/RED marking 68 | int debug_; //debug more(true) or not(false) 69 | }; 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /scripts/CDF_cache.tcl: -------------------------------------------------------------------------------- 1 | 1 1 0 2 | 1 1 0.35 3 | 2 1 0.4 4 | 7 1 0.46 5 | 13 1 0.5 6 | 67 1 0.6 7 | 133 1 0.7 8 | 667 1 0.78 9 | 1333 1 0.8 10 | 2000 1 0.9 11 | 2667 1 0.99 12 | 33333 1 1 13 | -------------------------------------------------------------------------------- /scripts/CDF_dctcp.tcl: -------------------------------------------------------------------------------- 1 | 6 1 0 2 | 6 1 0.15 3 | 13 1 0.2 4 | 19 1 0.3 5 | 33 1 0.4 6 | 53 1 0.53 7 | 133 1 0.6 8 | 667 1 0.7 9 | 1333 1 0.8 10 | 3333 1 0.9 11 | 6667 1 0.97 12 | 20000 1 1 13 | 14 | -------------------------------------------------------------------------------- /scripts/CDF_hadoop.tcl: -------------------------------------------------------------------------------- 1 | 1 1 0 2 | 24 1 0.1 3 | 30 1 0.2 4 | 33 1 0.3 5 | 33 1 0.4 6 | 50 1 0.5 7 | 53 1 0.6 8 | 67 1 0.7 9 | 120 1 0.8 10 | 160 1 0.9 11 | 200 1 0.95 12 | 667 1 0.96 13 | 6667 1 0.97 14 | 66667 1 0.99 15 | 333333 1 1 16 | -------------------------------------------------------------------------------- /scripts/CDF_vl2.tcl: -------------------------------------------------------------------------------- 1 | 1 1 0 2 | 1 1 0.5 3 | 2 1 0.6 4 | 3 1 0.7 5 | 7 1 0.8 6 | 267 1 0.9 7 | 2107 1 0.95 8 | 66667 1 0.99 9 | 666667 1 1 -------------------------------------------------------------------------------- /scripts/result.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import string 4 | import argparse 5 | 6 | #Get average FCT 7 | def avg(flows): 8 | sum=0.0 9 | for f in flows: 10 | sum=sum+f 11 | if len(flows)>0: 12 | return sum/len(flows) 13 | else: 14 | return 0 15 | 16 | #GET mean FCT 17 | def mean(flows): 18 | flows.sort() 19 | if len(flows)>0: 20 | return flows[50*len(flows)/100] 21 | else: 22 | return 0 23 | 24 | #GET 99% FCT 25 | def max(flows): 26 | flows.sort() 27 | if len(flows)>0: 28 | return flows[99*len(flows)/100] 29 | else: 30 | return 0 31 | 32 | 33 | parser = argparse.ArgumentParser() 34 | parser.add_argument("-i", "--input", help="input file name") 35 | parser.add_argument("-a","--all",help="print all FCT information",action="store_true") 36 | parser.add_argument("-o","--overall",help="print overall FCT information",action="store_true") 37 | parser.add_argument("-s","--small",help="print FCT information for short flows",action="store_true") 38 | parser.add_argument("-m","--median",help="print FCT information for median flows",action="store_true") 39 | parser.add_argument("-l","--large",help="print FCT information for large flows",action="store_true") 40 | parser.add_argument("--avg",help="only print average FCT information for flows in specific ranges",action="store_true") 41 | parser.add_argument("--tail",help="only print tail (99th percentile) FCT information for flows in specific ranges",action="store_true") 42 | 43 | #All the flows 44 | flows=[] 45 | flows_notimeouts=[]; #Flows without timeouts 46 | #Short flows (0,100KB) 47 | short_flows=[] 48 | short_flows_notimeouts=[]; 49 | #Large flows (10MB,) 50 | large_flows=[] 51 | large_flows_notimeouts=[]; 52 | #Median flows (100KB, 10MB) 53 | median_flows=[] 54 | median_flows_notimeouts=[]; 55 | #The number of total timeouts 56 | timeouts=0 57 | 58 | args = parser.parse_args() 59 | if args.input: 60 | fp = open(args.input) 61 | #Get overall average normalized FCT 62 | while True: 63 | line=fp.readline() 64 | if not line: 65 | break 66 | if len(line.split())<3: 67 | continue 68 | pkt_size=int(float(line.split()[0])) 69 | byte_size=float(pkt_size)*1460 70 | time=float(line.split()[1]) 71 | result=time*1000 72 | 73 | #TCP timeouts 74 | timeouts_num=int(line.split()[2]) 75 | timeouts+=timeouts_num 76 | 77 | flows.append(result) 78 | #If the flow is a short flow 79 | if byte_size<100*1024: 80 | short_flows.append(result) 81 | #If the flow is a large flow 82 | elif byte_size>10*1024*1024: 83 | large_flows.append(result) 84 | else: 85 | median_flows.append(result) 86 | 87 | #If this flow does not have timeout 88 | if timeouts_num==0: 89 | flows_notimeouts.append(result) 90 | #If the flow is a short flow 91 | if byte_size<100*1024: 92 | short_flows_notimeouts.append(result) 93 | #If the flow is a large flow 94 | elif byte_size>10*1024*1024: 95 | large_flows_notimeouts.append(result) 96 | else: 97 | median_flows_notimeouts.append(result) 98 | 99 | fp.close() 100 | 101 | if args.all: 102 | print "There are "+str(len(flows))+" flows in total" 103 | print "There are "+str(timeouts)+" TCP timeouts in total" 104 | print "Overall average FCT is:\n"+str(avg(flows)) 105 | print "Average FCT for "+str(len(short_flows))+" flows in (0,100KB)\n"+str(avg(short_flows)) 106 | print "99th percentile FCT for "+str(len(short_flows))+" flows in (0,100KB)\n"+str(max(short_flows)) 107 | print "Average FCT for "+str(len(median_flows))+" flows in (100KB,10MB)\n"+str(avg(median_flows)) 108 | print "Average FCT for "+str(len(large_flows))+" flows in (10MB,)\n"+str(avg(large_flows)) 109 | 110 | #Overall FCT information 111 | if args.overall: 112 | #Only average FCT information 113 | if args.avg and not args.tail: 114 | print "Overall average FCT is:\n"+str(avg(flows)) 115 | #Only tail FCT information 116 | elif not args.avg and args.tail: 117 | print "Overall 99th percentile FCT is:\n"+str(max(flows)) 118 | else: 119 | print "Overall average FCT is:\n"+str(avg(flows)) 120 | print "Overall 99th percentile FCT is:\n"+str(max(flows)) 121 | 122 | #FCT information for short flows 123 | if args.small: 124 | #Only average FCT information 125 | if args.avg and not args.tail: 126 | print "Average FCT for flows in (0,100KB) is:\n"+str(avg(short_flows)) 127 | #Only tail FCT information 128 | elif not args.avg and args.tail: 129 | print "99th percentile FCT for flows in (0,100KB) is:\n"+str(max(short_flows)) 130 | else: 131 | print "Average FCT for flows in (0,100KB) is:\n"+str(avg(short_flows)) 132 | print "99th percentile FCT for flows in (0,100KB) is:\n"+str(max(short_flows)) 133 | 134 | #FCT information for median flows 135 | if args.median: 136 | #Only average FCT information 137 | if args.avg and not args.tail: 138 | print "Average FCT for flows in (100KB,10MB) is:\n"+str(avg(median_flows)) 139 | #Only tail FCT information 140 | elif not args.avg and args.tail: 141 | print "99th percentile FCT for flows in (100KB,10MB) is:\n"+str(max(median_flows)) 142 | else: 143 | print "Average FCT for flows in (100KB,10MB) is:\n"+str(avg(median_flows)) 144 | print "99th percentile FCT for flows in (100KB,10MB) is:\n"+str(max(median_flows)) 145 | 146 | #FCT information for large flows 147 | if args.large: 148 | #Only average FCT information 149 | if args.avg and not args.tail: 150 | print "Average FCT for flows in (10MB,) is:\n"+str(avg(large_flows)) 151 | #Only tail FCT information 152 | elif not args.avg and args.tail: 153 | print "99th percentile FCT for flows in (10MB,) is:\n"+str(max(large_flows)) 154 | else: 155 | print "Average FCT for flows in (10MB,) is:\n"+str(avg(large_flows)) 156 | print "99th percentile FCT for flows in (10MB,) is:\n"+str(max(large_flows)) 157 | 158 | 159 | #print "There are "+str(len(flows_notimeouts))+" flows w/o timeouts in total" 160 | #print "Overall average FCT w/o timeouts: "+str(avg(flows_notimeouts)) 161 | #print "Average FCT (0,100KB) w/o timeouts: "+str(len(short_flows_notimeouts))+" flows "+str(avg(short_flows_notimeouts)) 162 | #print "99th percentile FCT (0,100KB): "+str(len(short_flows_notimeouts))+" flows "+str(max(short_flows_notimeouts)) 163 | #print "Average FCT (100KB,10MB) w/o timeouts: "+str(len(median_flows_notimeouts))+" flows "+str(avg(median_flows_notimeouts)) 164 | #print "Average FCT (10MB,) w/o timeouts: "+str(len(large_flows_notimeouts))+" flows "+str(avg(large_flows_notimeouts)) 165 | -------------------------------------------------------------------------------- /scripts/run_simulation_diffserv.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import os 3 | import Queue 4 | 5 | def worker(): 6 | while True: 7 | try: 8 | j = q.get(block = 0) 9 | except Queue.Empty: 10 | return 11 | #Make directory to save results 12 | os.system('mkdir '+j[1]) 13 | os.system(j[0]) 14 | 15 | q = Queue.Queue() 16 | 17 | service_num_arr = [8, 32] #Number of queues/services 18 | sim_end = 50000 #Number of flows generated in the simulation 19 | link_rate = 10 #The capacity of edge links 20 | mean_link_delay = 0.0000002 #Link delay 21 | host_delay = 0.000020 #Processing delay at end hosts 22 | queueSize = 200 #Switch port buffer size 23 | load_arr = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9] #Network loads 24 | connections_per_pair = 1 25 | 26 | enableMultiPath = 1 27 | perflowMP = 1 #Per-flow load balancing (ECMP) 28 | 29 | init_window = 16 #TCP initial window 30 | sourceAlg = 'DCTCP-Sack' #DCTCP-Sack (DCTCP) or Sack (ECN*) 31 | ackRatio = 1 32 | slowstartrestart = 'true' 33 | DCTCP_g = 0.0625 #g for DCTCP 34 | min_rto = 0.005 #TCP RTOmin 35 | 36 | #per-queue-standard(0), per-port(1), MQ-ECN(2) and per-queue-min(3) 37 | ECN_scheme_arr = [0, 2, 3] #ECN marking schemes 38 | DCTCP_K = 65.0 #Standard marking threshold in packets 39 | switchAlgs = ['DWRR','WRR'] #Scheduling algorithms 40 | 41 | topology_spt = 12 #Number of servers under a ToR switch 42 | topology_tors = 12 #Number of ToR switches 43 | topology_spines = 12 #Number of core switches 44 | topology_x = 1 #Oversubscription 45 | 46 | ns_path = '../ns-allinone-2.35/ns-2.35/ns' #Path of NS2 simulator 47 | sim_script = 'spine_empirical_diffserv.tcl' #Path of the simulation script 48 | specialStr = '' 49 | 50 | #For different scheduling algorithms 51 | for switchAlg in switchAlgs: 52 | #For different numbers of queues (services): 53 | for service_num in service_num_arr: 54 | #For different loads 55 | for load in load_arr: 56 | #For different ECN marking schemes 57 | for ECN_scheme in ECN_scheme_arr: 58 | #Transport protocol: TCP(ECN*) or DCTCP 59 | transport='tcp' 60 | if 'DCTCP' in sourceAlg: 61 | transport = 'dctcp' 62 | 63 | #Directory name: workload_transport_scheme_[ECN_scheme]_load_[load]_service_[service_num] 64 | directory_name = 'diffserv_'+specialStr+switchAlg+'_'+transport+'_scheme_'+str(ECN_scheme)+'_load_'+str(int(load*100))+'_service_'+str(service_num) 65 | directory_name = directory_name.lower() 66 | #Simulation command 67 | cmd = ns_path+' '+sim_script+' '\ 68 | +str(service_num)+' '\ 69 | +str(sim_end)+' '\ 70 | +str(link_rate)+' '\ 71 | +str(mean_link_delay)+' '\ 72 | +str(host_delay)+' '\ 73 | +str(queueSize)+' '\ 74 | +str(load)+' '\ 75 | +str(connections_per_pair)+' '\ 76 | +str(enableMultiPath)+' '\ 77 | +str(perflowMP)+' '\ 78 | +str(init_window)+' '\ 79 | +str(sourceAlg)+' '\ 80 | +str(ackRatio)+' '\ 81 | +str(slowstartrestart)+' '\ 82 | +str(DCTCP_g)+' '\ 83 | +str(min_rto)+' '\ 84 | +str(ECN_scheme)+' '\ 85 | +str(DCTCP_K)+' '\ 86 | +str(switchAlg)+' '\ 87 | +str(topology_spt)+' '\ 88 | +str(topology_tors)+' '\ 89 | +str(topology_spines)+' '\ 90 | +str(topology_x)+' '\ 91 | +str('./'+directory_name+'/flow.tr')+' >'\ 92 | +str('./'+directory_name+'/logFile.tr') 93 | 94 | q.put([cmd, directory_name]) 95 | 96 | #Create all worker threads 97 | threads = [] 98 | number_worker_threads = 20 99 | 100 | #Start threads to process jobs 101 | for i in range(number_worker_threads): 102 | t = threading.Thread(target = worker) 103 | threads.append(t) 104 | t.start() 105 | 106 | #Join all completed threads 107 | for t in threads: 108 | t.join() 109 | -------------------------------------------------------------------------------- /scripts/spine_empirical_diffserv.tcl: -------------------------------------------------------------------------------- 1 | source "tcp-common-opt-raw.tcl" 2 | 3 | set ns [new Simulator] 4 | set sim_start [clock seconds] 5 | puts "Host: [exec uname -a]" 6 | 7 | if {$argc != 24} { 8 | puts "wrong number of arguments $argc" 9 | exit 0 10 | } 11 | 12 | set service_num [lindex $argv 0] 13 | set sim_end [lindex $argv 1] 14 | set link_rate [lindex $argv 2] 15 | set mean_link_delay [lindex $argv 3] 16 | set host_delay [lindex $argv 4] 17 | set queueSize [lindex $argv 5] 18 | set load [lindex $argv 6] 19 | set connections_per_pair [lindex $argv 7] 20 | 21 | #### Multipath 22 | set enableMultiPath [lindex $argv 8] 23 | set perflowMP [lindex $argv 9] 24 | 25 | #### Transport settings options 26 | set init_window [lindex $argv 10] ; # TCP initial window 27 | set sourceAlg [lindex $argv 11] ; # Sack or DCTCP-Sack 28 | set ackRatio [lindex $argv 12] 29 | set slowstartrestart [lindex $argv 13] 30 | set DCTCP_g [lindex $argv 14] ; # DCTCP alpha estimation gain 31 | set min_rto [lindex $argv 15] 32 | 33 | #### Switch side options 34 | #per-queue standard (0), per-port (1), MQ-ECN (2) and per-queue-min (3) 35 | set ECN_scheme [lindex $argv 16] 36 | set DCTCP_K [lindex $argv 17] 37 | set switchAlg [lindex $argv 18] 38 | 39 | #### topology 40 | set topology_spt [lindex $argv 19] 41 | set topology_tors [lindex $argv 20] 42 | set topology_spines [lindex $argv 21] 43 | set topology_x [lindex $argv 22] 44 | 45 | #### FCT log file 46 | set fct_log [lindex $argv 23] 47 | 48 | #### Flow size distribution CDF file 49 | set pktSize 1460; #packet size in bytes 50 | set dwrr_quantum [expr $pktSize + 40]; #quantum for each queue (DWRR) 51 | set wrr_quantum [expr $pktSize + 40]; #weight for each queue (WRR) 52 | set link_capacity_unit Gb 53 | 54 | puts "Simulation input:" 55 | puts "Dynamic Flow - Pareto" 56 | puts "topology: spines server per rack = $topology_spt, x = $topology_x" 57 | puts "service number $service_num" 58 | puts "sim_end $sim_end" 59 | puts "link_rate $link_rate Gbps" 60 | puts "link_delay $mean_link_delay sec" 61 | puts "RTT [expr $mean_link_delay * 2.0 * 6] sec" 62 | puts "host_delay $host_delay sec" 63 | puts "queue size $queueSize pkts" 64 | puts "load $load" 65 | puts "connections_per_pair $connections_per_pair" 66 | puts "enableMultiPath=$enableMultiPath, perflowMP=$perflowMP" 67 | puts "initial window: $init_window" 68 | puts "source algorithm: $sourceAlg" 69 | puts "ackRatio $ackRatio" 70 | puts "DCTCP_g $DCTCP_g" 71 | puts "slow-start Restart $slowstartrestart" 72 | puts "ECN marking scheme $ECN_scheme" 73 | puts "DCTCP_K_ $DCTCP_K" 74 | puts "switchAlg $switchAlg" 75 | puts "pktSize(payload) $pktSize Bytes" 76 | puts "pktSize(include header) [expr $pktSize + 40] Bytes" 77 | puts "service number $service_num" 78 | puts "FCT log file $fct_log" 79 | puts " " 80 | 81 | ################# Transport Options #################### 82 | Agent/TCP set windowInit_ $init_window 83 | Agent/TCP set window_ 1256 84 | Agent/TCP set ecn_ 1 85 | Agent/TCP set old_ecn_ 1 86 | Agent/TCP set packetSize_ $pktSize 87 | Agent/TCP/FullTcp set segsize_ $pktSize 88 | Agent/TCP/FullTcp set spa_thresh_ 0 89 | 90 | Agent/TCP set slow_start_restart_ $slowstartrestart 91 | Agent/TCP set windowOption_ 0 92 | Agent/TCP set tcpTick_ 0.000001 93 | Agent/TCP set minrto_ $min_rto 94 | Agent/TCP set rtxcur_init_ $min_rto; #RTO init value 95 | Agent/TCP set maxrto_ 64 96 | 97 | Agent/TCP/FullTcp set nodelay_ true; #disable Nagle 98 | Agent/TCP/FullTcp set segsperack_ $ackRatio 99 | Agent/TCP/FullTcp set interval_ 0 100 | 101 | 102 | if {[string compare $sourceAlg "DCTCP-Sack"] == 0} { 103 | Agent/TCP set dctcp_ true 104 | Agent/TCP set dctcp_g_ $DCTCP_g 105 | } 106 | 107 | ################# Switch Options ###################### 108 | Queue set limit_ $queueSize 109 | 110 | Queue/DWRR set queue_num_ $service_num 111 | Queue/DWRR set mean_pktsize_ [expr $pktSize + 40] 112 | Queue/DWRR set port_thresh_ $DCTCP_K 113 | Queue/DWRR set estimate_round_alpha_ 0.75 114 | Queue/DWRR set estimate_round_idle_interval_bytes_ 1500 115 | Queue/DWRR set link_capacity_ $link_rate$link_capacity_unit 116 | Queue/DWRR set deque_marking_ false 117 | Queue/DWRR set debug_ false 118 | 119 | Queue/WRR set queue_num_ $service_num 120 | Queue/WRR set mean_pktsize_ [expr $pktSize + 40] 121 | Queue/WRR set port_thresh_ $DCTCP_K 122 | Queue/WRR set estimate_round_alpha_ 0.75 123 | Queue/WRR set estimate_round_idle_interval_bytes_ 1500 124 | Queue/WRR set link_capacity_ $link_rate$link_capacity_unit 125 | Queue/WRR set deque_marking_ false 126 | Queue/WRR set debug_ false 127 | 128 | if {$ECN_scheme != 3} { 129 | Queue/DWRR set marking_scheme_ $ECN_scheme 130 | Queue/WRR set marking_scheme_ $ECN_scheme 131 | } else { 132 | #Per-queue-min 133 | Queue/DWRR set marking_scheme_ 0 134 | Queue/WRR set marking_scheme_ 0 135 | } 136 | 137 | ############## Multipathing ########################### 138 | if {$enableMultiPath == 1} { 139 | $ns rtproto DV 140 | Agent/rtProto/DV set advertInterval [expr 2 * $sim_end] 141 | Node set multiPath_ 1 142 | if {$perflowMP != 0} { 143 | Classifier/MultiPath set perflow_ 1 144 | } 145 | } 146 | 147 | ############# Topoplgy ######################### 148 | set S [expr $topology_spt * $topology_tors] ; #number of servers 149 | set UCap [expr $link_rate * $topology_spt / $topology_spines / $topology_x] ; #uplink rate 150 | puts "Total server number: $S" 151 | puts "Uplink capacity: $UCap Gbps" 152 | 153 | for {set i 0} {$i < $S} {incr i} { 154 | set s($i) [$ns node] 155 | } 156 | 157 | for {set i 0} {$i < $topology_tors} {incr i} { 158 | set n($i) [$ns node] 159 | } 160 | 161 | for {set i 0} {$i < $topology_spines} {incr i} { 162 | set a($i) [$ns node] 163 | } 164 | 165 | for {set i 0} {$i < $S} {incr i} { 166 | set j [expr $i / $topology_spt] 167 | $ns duplex-link $s($i) $n($j) [set link_rate]Gb [expr $host_delay + $mean_link_delay] $switchAlg 168 | 169 | ##### Configure DWRR/WRR for edge links ##### 170 | set L [$ns link $s($i) $n($j)] 171 | set q [$L set queue_] 172 | 173 | for {set service_i 0} {$service_i < $service_num} {incr service_i} { 174 | 175 | if {[string compare $switchAlg "DWRR"] == 0} { 176 | $q set-quantum $service_i $dwrr_quantum 177 | } elseif {[string compare $switchAlg "WRR"] == 0} { 178 | $q set-quantum $service_i $wrr_quantum 179 | } 180 | 181 | #per-queue min (3) 182 | if {$ECN_scheme == 3} { 183 | $q set-thresh $service_i [expr $DCTCP_K / $service_num] 184 | } else { 185 | $q set-thresh $service_i [expr $DCTCP_K] 186 | } 187 | } 188 | 189 | set L [$ns link $n($j) $s($i)] 190 | set q [$L set queue_] 191 | 192 | for {set service_i 0} {$service_i < $service_num} {incr service_i} { 193 | if {[string compare $switchAlg "DWRR"] == 0} { 194 | $q set-quantum $service_i $dwrr_quantum 195 | } elseif {[string compare $switchAlg "WRR"] == 0} { 196 | $q set-quantum $service_i $wrr_quantum 197 | } 198 | 199 | #per-queue min (3) 200 | if {$ECN_scheme == 3} { 201 | $q set-thresh $service_i [expr $DCTCP_K / $service_num] 202 | } else { 203 | $q set-thresh $service_i [expr $DCTCP_K] 204 | } 205 | } 206 | } 207 | 208 | for {set i 0} {$i < $topology_tors} {incr i} { 209 | for {set j 0} {$j < $topology_spines} {incr j} { 210 | $ns duplex-link $n($i) $a($j) [set UCap]Gb $mean_link_delay $switchAlg 211 | 212 | ##### Configure DWRR/WRR for core links ##### 213 | set L [$ns link $n($i) $a($j)] 214 | set q [$L set queue_] 215 | $q set link_capacity_ $UCap$link_capacity_unit 216 | 217 | for {set service_i 0} {$service_i < $service_num} {incr service_i} { 218 | if {[string compare $switchAlg "DWRR"] == 0} { 219 | $q set-quantum $service_i $dwrr_quantum 220 | } elseif {[string compare $switchAlg "WRR"] == 0} { 221 | $q set-quantum $service_i $wrr_quantum 222 | } 223 | 224 | #per-queue min (3) 225 | if {$ECN_scheme == 3} { 226 | $q set-thresh $service_i [expr $DCTCP_K / $service_num] 227 | } else { 228 | $q set-thresh $service_i [expr $DCTCP_K] 229 | } 230 | } 231 | 232 | set L [$ns link $a($j) $n($i)] 233 | set q [$L set queue_] 234 | $q set link_capacity_ $UCap$link_capacity_unit 235 | 236 | for {set service_i 0} {$service_i < $service_num} {incr service_i} { 237 | if {[string compare $switchAlg "DWRR"] == 0} { 238 | $q set-quantum $service_i $dwrr_quantum 239 | } elseif {[string compare $switchAlg "WRR"] == 0} { 240 | $q set-quantum $service_i $wrr_quantum 241 | } 242 | 243 | #per-queue min (3) 244 | if {$ECN_scheme == 3} { 245 | $q set-thresh $service_i [expr $DCTCP_K / $service_num] 246 | } else { 247 | $q set-thresh $service_i [expr $DCTCP_K] 248 | } 249 | } 250 | } 251 | } 252 | 253 | 254 | ############# Agents ######################### 255 | #set lambda [expr ($link_rate*$load*1000000000)/($meanFlowSize*8.0)] 256 | #set lambda [expr ($link_rate*$load*1000000000)/($mean_npkts*($pktSize+40)*8.0)] 257 | #puts "Arrival: Poisson with inter-arrival [expr 1/$lambda * 1000] ms" 258 | #puts "FlowSize: Pareto with mean = $meanFlowSize, shape = $paretoShape" 259 | 260 | puts "Setting up connections ..."; flush stdout 261 | 262 | set flow_gen 0 263 | set flow_fin 0 264 | 265 | set flowlog [open $fct_log w] 266 | set init_fid 0 267 | 268 | for {set j 0} {$j < $S } {incr j} { 269 | for {set i 0} {$i < $S } {incr i} { 270 | if {$i != $j} { 271 | set agtagr($i,$j) [new Agent_Aggr_pair] 272 | 273 | #Assign service ID 274 | set service_id [expr {(($j + 1) * $S + ($i + 1)) % $service_num}] 275 | $agtagr($i,$j) setup $s($i) $s($j) "$i $j" $connections_per_pair $init_fid $service_id "TCP_pair" 276 | $agtagr($i,$j) attach-logfile $flowlog 277 | 278 | #Assign flow size distribution 279 | set flow_cdf "CDF_vl2.tcl" 280 | set meanFlowSize 7495019 281 | set dist "vl2" 282 | 283 | #Currently, we have 4 flow size distributions in total 284 | if {$service_id % 4 == 0} { 285 | set flow_cdf "CDF_cache.tcl" 286 | set meanFlowSize 913703 287 | set dist "cache" 288 | } elseif {$service_id % 4 == 1} { 289 | set flow_cdf "CDF_dctcp.tcl" 290 | set meanFlowSize 1671357 291 | set dist "dctcp" 292 | } elseif {$service_id % 4 == 2} { 293 | set flow_cdf "CDF_hadoop.tcl" 294 | set meanFlowSize 4149016 295 | set dist "hadoop" 296 | } 297 | 298 | set lambda [expr ($link_rate * $load * 1000000000) / ($meanFlowSize * 8.0)] 299 | puts -nonewline "($i,$j) service $service_id $dist " 300 | 301 | #For Poisson 302 | $agtagr($i,$j) set_PCarrival_process [expr $lambda/($S - 1)] $flow_cdf [expr 17 * $i + 1244 * $j] [expr 33 * $i + 4369 * $j] 303 | $ns at 0.1 "$agtagr($i,$j) warmup 0.5 5" 304 | $ns at 1 "$agtagr($i,$j) init_schedule" 305 | 306 | set init_fid [expr $init_fid + $connections_per_pair]; 307 | } 308 | } 309 | } 310 | 311 | puts "Initial agent creation done";flush stdout 312 | puts "Simulation started!" 313 | 314 | $ns run 315 | -------------------------------------------------------------------------------- /scripts/tcp-common-opt-raw.tcl: -------------------------------------------------------------------------------- 1 | # 2 | # TCP pair's have 3 | # - group_id = "src->dst" 4 | # - pair_id = index of connection among the group 5 | # - fid = unique flow identifier for this connection (group_id, pair_id) 6 | # 7 | set next_fid 0 8 | 9 | Class TCP_pair 10 | 11 | #Variables: 12 | #tcps tcpr: Sender TCP, Receiver TCP 13 | #sn dn : source/dest node which TCP sender/receiver exist 14 | #: (only for setup_wnode) 15 | #delay : delay between sn and san (dn and dan) 16 | #: (only for setup_wnode) 17 | #san dan : nodes to which sn/dn are attached 18 | #aggr_ctrl: Agent_Aggr_pair for callback 19 | #start_cbfunc: callback at start 20 | #fin_cbfunc: callback at start 21 | #group_id : group id 22 | #pair_id : group id 23 | #fid : flow id 24 | #Public Functions: 25 | #setup{snode dnode} <- either of them 26 | #setup_wnode{snode dnode} <- must be called 27 | #setgid {gid} <- if applicable (default 0) 28 | #setpairid {pid} <- if applicable (default 0) 29 | #setfid {fid} <- if applicable (default 0) 30 | #start { nr_bytes } ;# let start sending nr_bytes 31 | #set_debug_mode { mode } ;# change to debug_mode 32 | #setcallback { controller } #; only Agent_Aggr_pair uses to 33 | ##; registor itself 34 | #fin_notify {} #; Callback .. this is called 35 | ##; by agent when it finished 36 | #Private Function 37 | #flow_finished {} { 38 | 39 | TCP_pair instproc init {args} { 40 | $self instvar pair_id group_id id debug_mode rttimes 41 | $self instvar tcps tcpr;# Sender TCP, Receiver TCP 42 | global myAgent 43 | eval $self next $args 44 | 45 | $self set tcps [new Agent/TCP/FullTcp/Sack] ;# Sender TCP 46 | $self set tcpr [new Agent/TCP/FullTcp/Sack] ;# Receiver TCP 47 | 48 | $tcps set_callback $self 49 | #$tcpr set_callback $self 50 | 51 | $self set pair_id 0 52 | $self set group_id 0 53 | $self set id 0 54 | $self set debug_mode 1 55 | $self set rttimes 0 56 | } 57 | 58 | TCP_pair instproc set_debug_mode { mode } { 59 | $self instvar debug_mode 60 | $self set debug_mode $mode 61 | } 62 | 63 | 64 | TCP_pair instproc setup {snode dnode} { 65 | #Directly connect agents to snode, dnode. 66 | #For faster simulation. 67 | global ns link_rate 68 | $self instvar tcps tcpr;# Sender TCP, Receiver TCP 69 | $self instvar san dan ;# memorize dumbell node (to attach) 70 | 71 | $self set san $snode 72 | $self set dan $dnode 73 | 74 | $ns attach-agent $snode $tcps; 75 | $ns attach-agent $dnode $tcpr; 76 | 77 | $tcpr listen 78 | $ns connect $tcps $tcpr 79 | } 80 | 81 | TCP_pair instproc create_agent {} { 82 | $self instvar tcps tcpr;# Sender TCP, Receiver TCP 83 | $self set tcps [new Agent/TCP/FullTcp/Sack] ;# Sender TCP 84 | $self set tcpr [new Agent/TCP/FullTcp/Sack] ;# Receiver TCP 85 | } 86 | 87 | TCP_pair instproc setup_wnode {snode dnode link_dly} { 88 | 89 | #New nodes are allocated for sender/receiver agents. 90 | #They are connected to snode/dnode with link having delay of link_dly. 91 | #Caution: If the number of pairs is large, simulation gets way too slow, 92 | #and memory consumption gets very very large.. 93 | #Use "setup" if possible in such cases. 94 | 95 | global ns link_rate 96 | $self instvar sn dn ;# Source Node, Dest Node 97 | $self instvar tcps tcpr;# Sender TCP, Receiver TCP 98 | $self instvar san dan ;# memorize dumbell node (to attach) 99 | $self instvar delay ;# local link delay 100 | 101 | $self set delay link_dly 102 | 103 | $self set sn [$ns node] 104 | $self set dn [$ns node] 105 | 106 | $self set san $snode 107 | $self set dan $dnode 108 | 109 | $ns duplex-link $snode $sn [set link_rate]Gb $delay DropTail 110 | $ns duplex-link $dn $dnode [set link_rate]Gb $delay DropTail 111 | 112 | $ns attach-agent $sn $tcps; 113 | $ns attach-agent $dn $tcpr; 114 | 115 | $tcpr listen 116 | $ns connect $tcps $tcpr 117 | } 118 | 119 | TCP_pair instproc set_fincallback { controller func} { 120 | $self instvar aggr_ctrl fin_cbfunc 121 | $self set aggr_ctrl $controller 122 | $self set fin_cbfunc $func 123 | } 124 | 125 | TCP_pair instproc set_startcallback { controller func} { 126 | $self instvar aggr_ctrl start_cbfunc 127 | $self set aggr_ctrl $controller 128 | $self set start_cbfunc $func 129 | } 130 | 131 | TCP_pair instproc setgid { gid } { 132 | $self instvar group_id 133 | $self set group_id $gid 134 | } 135 | 136 | TCP_pair instproc setpairid { pid } { 137 | $self instvar pair_id 138 | $self set pair_id $pid 139 | } 140 | 141 | TCP_pair instproc setfid { fid } { 142 | $self instvar tcps tcpr 143 | $self instvar id 144 | $self set id $fid 145 | $tcps set fid_ $fid; 146 | $tcpr set fid_ $fid; 147 | } 148 | 149 | TCP_pair instproc setserviceid {sid} { 150 | $self instvar tcps tcpr 151 | $self instvar service_id 152 | $self set service_id $sid 153 | $tcps set serviceid_ $sid; 154 | $tcpr set serviceid_ $sid; 155 | } 156 | 157 | 158 | TCP_pair instproc set_debug_mode { mode } { 159 | $self instvar debug_mode 160 | $self set debug_mode $mode 161 | } 162 | TCP_pair instproc start { nr_bytes } { 163 | global ns sim_end flow_gen 164 | $self instvar tcps tcpr id group_id 165 | $self instvar start_time bytes 166 | $self instvar aggr_ctrl start_cbfunc 167 | 168 | $self instvar debug_mode 169 | 170 | $self set start_time [$ns now] ;# memorize 171 | $self set bytes $nr_bytes ;# memorize 172 | 173 | if {$flow_gen >= $sim_end} { 174 | return 175 | } 176 | if {$start_time >= 0.2} { 177 | set flow_gen [expr $flow_gen + 1] 178 | } 179 | 180 | if { $debug_mode == 1 } { 181 | puts "stats: [$ns now] start grp $group_id fid $id $nr_bytes bytes" 182 | } 183 | 184 | if { [info exists aggr_ctrl] } { 185 | $aggr_ctrl $start_cbfunc 186 | } 187 | 188 | $tcps set signal_on_empty_ TRUE 189 | $tcps advance-bytes $nr_bytes 190 | } 191 | 192 | TCP_pair instproc warmup { nr_pkts } { 193 | global ns 194 | $self instvar tcps id group_id 195 | 196 | $self instvar debug_mode 197 | 198 | set pktsize [$tcps set packetSize_] 199 | 200 | if { $debug_mode == 1 } { 201 | puts "warm-up: [$ns now] start grp $group_id fid $id $nr_pkts pkts ($pktsize +40)" 202 | } 203 | 204 | $tcps advanceby $nr_pkts 205 | } 206 | 207 | 208 | TCP_pair instproc stop {} { 209 | $self instvar tcps tcpr 210 | 211 | $tcps reset 212 | $tcpr reset 213 | } 214 | 215 | TCP_pair instproc fin_notify {} { 216 | global ns 217 | $self instvar sn dn san dan rttimes 218 | $self instvar tcps tcpr 219 | $self instvar aggr_ctrl fin_cbfunc 220 | $self instvar pair_id service_id 221 | $self instvar bytes 222 | 223 | $self instvar dt 224 | $self instvar bps 225 | 226 | $self flow_finished 227 | 228 | #Shuang 229 | set old_rttimes $rttimes 230 | $self set rttimes [$tcps set nrexmit_] 231 | 232 | # 233 | # Mohammad commenting these 234 | # for persistent connections 235 | # 236 | #$tcps reset 237 | #$tcpr reset 238 | 239 | if { [info exists aggr_ctrl] } { 240 | $aggr_ctrl $fin_cbfunc $pair_id $bytes $dt $bps [expr $rttimes - $old_rttimes] $service_id 241 | } 242 | } 243 | 244 | TCP_pair instproc flow_finished {} { 245 | global ns 246 | $self instvar start_time bytes id group_id 247 | $self instvar dt bps 248 | $self instvar debug_mode 249 | 250 | set ct [$ns now] 251 | #Shuang commenting these 252 | $self set dt [expr $ct - $start_time] 253 | if { $dt == 0 } { 254 | puts "dt = 0" 255 | flush stdout 256 | } 257 | $self set bps [expr $bytes * 8.0 / $dt ] 258 | 259 | if { $debug_mode == 1 } { 260 | puts "stats: $ct fin grp $group_id fid $id fldur $dt sec $bps bps" 261 | } 262 | } 263 | 264 | Agent/TCP/FullTcp instproc set_callback {tcp_pair} { 265 | $self instvar ctrl 266 | $self set ctrl $tcp_pair 267 | } 268 | 269 | Agent/TCP/FullTcp instproc done_data {} { 270 | global ns sink 271 | $self instvar ctrl 272 | #puts "[$ns now] $self fin-ack received"; 273 | if { [info exists ctrl] } { 274 | $ctrl fin_notify 275 | } 276 | } 277 | 278 | Class Agent_Aggr_pair 279 | #Note: 280 | #Contoller and placeholder of Agent_pairs 281 | #Let Agent_pairs to arrives according to 282 | #random process. 283 | #Currently, the following two processes are defined 284 | #- PParrival: 285 | #flow arrival is poissson and 286 | #each flow contains pareto 287 | #distributed number of packets. 288 | #- PEarrival 289 | #flow arrival is poissson and 290 | #each flow contains pareto 291 | #distributed number of packets. 292 | #- PBarrival 293 | #flow arrival is poissson and 294 | #each flow contains bimodal 295 | #distributed number of packets. 296 | 297 | #Variables:# 298 | #apair: array of Agent_pair 299 | #nr_pairs: the number of pairs 300 | #rv_flow_intval: (r.v.) flow interval 301 | #rv_nbytes: (r.v.) the number of bytes within a flow 302 | #last_arrival_time: the last flow starting time 303 | #logfile: log file (should have been opend) 304 | #stat_nr_finflow ;# statistics nr of finished flows 305 | #stat_sum_fldur ;# statistics sum of finished flow durations 306 | #last_arrival_time ;# last flow arrival time 307 | #actfl ;# nr of current active flow 308 | 309 | #Public functions: 310 | #attach-logfile {logf} <- call if want logfile 311 | #setup {snode dnode gid nr} <- must 312 | #set_PParrival_process {lambda mean_nbytes shape rands1 rands2} <- call either 313 | #set_PEarrival_process {lambda mean_nbytes rands1 rands2} <- 314 | #set_PBarrival_process {lambda mean_nbytes S1 S2 rands1 rands2} <- of them 315 | #init_schedule {} <- must 316 | 317 | #fin_notify { pid bytes fldur bps } ;# Callback 318 | #start_notify {} ;# Callback 319 | 320 | #Private functions: 321 | #init {args} 322 | #resetvars {} 323 | 324 | 325 | Agent_Aggr_pair instproc init {args} { 326 | eval $self next $args 327 | } 328 | 329 | 330 | Agent_Aggr_pair instproc attach-logfile { logf } { 331 | #Public 332 | $self instvar logfile 333 | $self set logfile $logf 334 | } 335 | 336 | Agent_Aggr_pair instproc setup {snode dnode gid nr init_fid sid agent_pair_type} { 337 | #Public 338 | #Note: 339 | #Create nr pairs of Agent_pair 340 | #and connect them to snode-dnode bottleneck. 341 | #We may refer this pair by group_id gid. 342 | #All Agent_pairs have the same gid, 343 | #and each of them has its own flow id: init_fid + [0 .. nr-1] 344 | #global next_fid 345 | 346 | $self instvar apair ;# array of Agent_pair 347 | $self instvar group_id ;# group id of this group (given) 348 | $self instvar nr_pairs ;# nr of pairs in this group (given) 349 | $self instvar service_id ;# service id of this group (given) 350 | $self instvar s_node d_node apair_type ; 351 | 352 | $self set group_id $gid 353 | $self set nr_pairs $nr 354 | $self set service_id $sid 355 | $self set s_node $snode 356 | $self set d_node $dnode 357 | $self set apair_type $agent_pair_type 358 | 359 | for {set i 0} {$i < $nr_pairs} {incr i} { 360 | $self set apair($i) [new $agent_pair_type] 361 | $apair($i) setup $snode $dnode 362 | $apair($i) setgid $group_id ;# let each pair know our group id 363 | $apair($i) setpairid $i ;# let each pair know his pair id 364 | $apair($i) setfid $init_fid ;# assign next fid 365 | $apair($i) setserviceid $service_id ;# let each pair know his service id 366 | incr init_fid 367 | } 368 | $self resetvars ;# other initialization 369 | } 370 | 371 | 372 | set warmupRNG [new RNG] 373 | $warmupRNG seed 5251 374 | 375 | Agent_Aggr_pair instproc warmup {jitter_period npkts} { 376 | global ns warmupRNG 377 | $self instvar nr_pairs apair 378 | 379 | for {set i 0} {$i < $nr_pairs} {incr i} { 380 | $ns at [expr [$ns now] + [$warmupRNG uniform 0.0 $jitter_period]] "$apair($i) warmup $npkts" 381 | } 382 | } 383 | 384 | Agent_Aggr_pair instproc init_schedule {} { 385 | #Public 386 | #Note: 387 | #Initially schedule flows for all pairs 388 | #according to the arrival process. 389 | global ns 390 | $self instvar nr_pairs apair 391 | 392 | # Mohammad: initializing last_arrival_time 393 | #$self instvar last_arrival_time 394 | #$self set last_arrival_time [$ns now] 395 | $self instvar tnext rv_flow_intval 396 | 397 | set dt [$rv_flow_intval value] 398 | 399 | $self set tnext [expr [$ns now] + $dt] 400 | 401 | for {set i 0} {$i < $nr_pairs} {incr i} { 402 | 403 | #### Callback Setting ######################## 404 | $apair($i) set_fincallback $self fin_notify 405 | $apair($i) set_startcallback $self start_notify 406 | ############################################### 407 | 408 | $self schedule $i 409 | } 410 | } 411 | 412 | 413 | Agent_Aggr_pair instproc set_PParrival_process {lambda mean_nbytes shape rands1 rands2} { 414 | #Public 415 | #setup random variable rv_flow_intval and rv_nbytes. 416 | #To get the r.v. call "value" function. 417 | #ex) $rv_flow_intval value 418 | 419 | #- PParrival: 420 | #flow arrival: poissson with rate $lambda 421 | #flow length : pareto with mean $mean_nbytes bytes and shape parameter $shape. 422 | 423 | $self instvar rv_flow_intval rv_nbytes 424 | 425 | set pareto_shape $shape 426 | set rng1 [new RNG] 427 | 428 | $rng1 seed $rands1 429 | $self set rv_flow_intval [new RandomVariable/Exponential] 430 | $rv_flow_intval use-rng $rng1 431 | $rv_flow_intval set avg_ [expr 1.0/$lambda] 432 | 433 | set rng2 [new RNG] 434 | $rng2 seed $rands2 435 | $self set rv_nbytes [new RandomVariable/Pareto] 436 | $rv_nbytes use-rng $rng2 437 | #$rv_nbytes set avg_ $mean_nbytes 438 | #Shuang: hack for pkt oriented 439 | $rv_nbytes set avg_ [expr $mean_nbytes/1500] 440 | $rv_nbytes set shape_ $pareto_shape 441 | } 442 | 443 | Agent_Aggr_pair instproc set_PEarrival_process {lambda mean_nbytes rands1 rands2} { 444 | 445 | #setup random variable rv_flow_intval and rv_nbytes. 446 | #To get the r.v. call "value" function. 447 | #ex) $rv_flow_intval value 448 | 449 | #- PEarrival 450 | #flow arrival: poissson with rate lambda 451 | #flow length : exp with mean mean_nbytes bytes. 452 | 453 | $self instvar rv_flow_intval rv_nbytes 454 | 455 | set rng1 [new RNG] 456 | $rng1 seed $rands1 457 | 458 | $self set rv_flow_intval [new RandomVariable/Exponential] 459 | $rv_flow_intval use-rng $rng1 460 | $rv_flow_intval set avg_ [expr 1.0/$lambda] 461 | 462 | 463 | set rng2 [new RNG] 464 | $rng2 seed $rands2 465 | $self set rv_nbytes [new RandomVariable/Exponential] 466 | $rv_nbytes use-rng $rng2 467 | $rv_nbytes set avg_ $mean_nbytes 468 | } 469 | Agent_Aggr_pair instproc set_PCarrival_process {lambda cdffile rands1 rands2} { 470 | #public 471 | ##setup random variable rv_flow_intval and rv_npkts. 472 | # 473 | #- PCarrival: 474 | #flow arrival: poisson with rate $lambda 475 | #flow length: custom defined expirical cdf 476 | 477 | $self instvar rv_flow_intval rv_nbytes 478 | 479 | set rng1 [new RNG] 480 | $rng1 seed $rands1 481 | 482 | $self set rv_flow_intval [new RandomVariable/Exponential] 483 | $rv_flow_intval use-rng $rng1 484 | $rv_flow_intval set avg_ [expr 1.0/$lambda] 485 | 486 | set rng2 [new RNG] 487 | $rng2 seed $rands2 488 | 489 | $self set rv_nbytes [new RandomVariable/Empirical] 490 | $rv_nbytes use-rng $rng2 491 | $rv_nbytes set interpolation_ 2 492 | $rv_nbytes loadCDF $cdffile 493 | } 494 | 495 | Agent_Aggr_pair instproc set_LCarrival_process {lambda cdffile rands1 rands2} { 496 | #public 497 | ##setup random variable rv_flow_intval and rv_npkts. 498 | # 499 | #- PCarrival: 500 | #flow arrival: lognormal with rate $lambda 501 | #flow length: custom defined expirical cdf 502 | 503 | $self instvar rv_flow_intval rv_nbytes 504 | 505 | set rng1 [new RNG] 506 | $rng1 seed $rands1 507 | 508 | $self set rv_flow_intval [new RandomVariable/LogNormal] 509 | $rv_flow_intval use-rng $rng1 510 | $rv_flow_intval set avg_ [expr 0.5 * log(1.0/($lambda*$lambda) / 5.0)] 511 | $rv_flow_intval set std_ [expr sqrt(log(5.0))] 512 | 513 | set rng2 [new RNG] 514 | $rng2 seed $rands2 515 | 516 | $self set rv_nbytes [new RandomVariable/Empirical] 517 | $rv_nbytes use-rng $rng2 518 | $rv_nbytes set interpolation_ 2 519 | $rv_nbytes loadCDF $cdffile 520 | } 521 | 522 | Agent_Aggr_pair instproc set_PBarrival_process {lambda mean_nbytes S1 S2 rands1 rands2} { 523 | #Public 524 | #setup random variable rv_flow_intval and rv_nbytes. 525 | #To get the r.v. call "value" function. 526 | #ex) $rv_flow_intval value 527 | 528 | #- PParrival: 529 | #flow arrival: poissson with rate $lambda 530 | #flow length : pareto with mean $mean_nbytes bytes and shape parameter $shape. 531 | 532 | $self instvar rv_flow_intval rv_nbytes 533 | 534 | set rng1 [new RNG] 535 | 536 | $rng1 seed $rands1 537 | $self set rv_flow_intval [new RandomVariable/Exponential] 538 | $rv_flow_intval use-rng $rng1 539 | $rv_flow_intval set avg_ [expr 1.0/$lambda] 540 | 541 | set rng2 [new RNG] 542 | 543 | $rng2 seed $rands2 544 | $self set rv_nbytes [new RandomVariable/Binomial] 545 | $rv_nbytes use-rng $rng2 546 | 547 | $rv_nbytes set p1_ [expr (1.0*$mean_nbytes - $S2)/($S1-$S2)] 548 | $rv_nbytes set s1_ $S1 549 | $rv_nbytes set s2_ $S2 550 | 551 | set p [expr (1.0*$mean_nbytes - $S2)/($S1-$S2)] 552 | if { $p < 0 } { 553 | puts "In PBarrival, prob for bimodal p_ is negative %p_ exiting.. " 554 | flush stdout 555 | exit 0 556 | } 557 | #else { 558 | # puts "# PBarrival S1: $S1 S2: $S2 p_: $p mean $mean_nbytes" 559 | #} 560 | 561 | } 562 | 563 | Agent_Aggr_pair instproc set_PFarrival_process {lambda mean_nbytes rand1} { 564 | #public 565 | #fixed interval 566 | #fixed flow size 567 | 568 | $self instvar rv_flow_intval rv_nbytes 569 | 570 | set rng1 [new RNG] 571 | $rng1 seed $rand1 572 | $self set rv_flow_intval [new RandomVariable/Exponential] 573 | $rv_flow_intval use-rng $rng1 574 | $rv_flow_intval set avg_ [expr 1.0/$lambda] 575 | 576 | set rng2 [new RNG] 577 | $rng2 seed 12345 578 | $self set rv_nbytes [new RandomVariable/Uniform] 579 | $rv_nbytes use-rng $rng2 580 | $rv_nbytes set min_ $mean_nbytes 581 | $rv_nbytes set max_ $mean_nbytes 582 | 583 | } 584 | 585 | Agent_Aggr_pair instproc resetvars {} { 586 | #Private 587 | #Reset variables 588 | # $self instvar fid ;# current flow id of this group 589 | $self instvar tnext ;# last flow arrival time 590 | $self instvar actfl ;# nr of current active flow 591 | 592 | $self set tnext 0.0 593 | # $self set fid 0 ;# flow id starts from 0 594 | $self set actfl 0 595 | } 596 | 597 | Agent_Aggr_pair instproc schedule { pid } { 598 | #Private 599 | #Note: 600 | #Schedule pair (having pid) next flow time 601 | #according to the flow arrival process. 602 | 603 | global ns flow_gen sim_end 604 | $self instvar apair 605 | # $self instvar fid 606 | $self instvar tnext 607 | $self instvar rv_flow_intval rv_nbytes 608 | 609 | if {$flow_gen >= $sim_end} { 610 | return 611 | } 612 | 613 | set t [$ns now] 614 | 615 | if { $t > $tnext } { 616 | puts "Error, Not enough flows ! Aborting! pair id $pid" 617 | flush stdout 618 | exit 619 | } 620 | 621 | # Mohammad: persistent connection.. don't 622 | # need to set fid each time 623 | #$apair($pid) setfid $fid 624 | # incr fid 625 | 626 | set tmp_ [expr ceil ([$rv_nbytes value])] 627 | set tmp_ [expr $tmp_ * 1460] 628 | $ns at $tnext "$apair($pid) start $tmp_" 629 | 630 | set dt [$rv_flow_intval value] 631 | $self set tnext [expr $tnext + $dt] 632 | $ns at [expr $tnext - 0.0000001] "$self check_if_behind" 633 | } 634 | 635 | Agent_Aggr_pair instproc check_if_behind {} { 636 | global ns 637 | global flow_gen sim_end 638 | $self instvar apair 639 | $self instvar nr_pairs 640 | $self instvar apair_type s_node d_node group_id service_id 641 | $self instvar tnext 642 | 643 | set t [$ns now] 644 | if { $flow_gen < $sim_end && $tnext < [expr $t + 0.0000002] } { #create new flow 645 | puts "[$ns now]: creating new connection $nr_pairs $s_node -> $d_node" 646 | flush stdout 647 | $self set apair($nr_pairs) [new $apair_type] 648 | $apair($nr_pairs) setup $s_node $d_node 649 | $apair($nr_pairs) setgid $group_id ; 650 | $apair($nr_pairs) setpairid $nr_pairs ; 651 | $apair($nr_pairs) setserviceid $service_id ;# let each pair know his service id 652 | 653 | #### Callback Setting ################# 654 | $apair($nr_pairs) set_fincallback $self fin_notify 655 | $apair($nr_pairs) set_startcallback $self start_notify 656 | ####################################### 657 | $self schedule $nr_pairs 658 | incr nr_pairs 659 | } 660 | 661 | } 662 | 663 | 664 | Agent_Aggr_pair instproc fin_notify { pid bytes fldur bps rttimes sid} { 665 | #Callback Function 666 | #pid : pair_id 667 | #bytes : nr of bytes of the flow which has just finished 668 | #fldur: duration of the flow which has just finished 669 | #bps : avg bits/sec of the flow which has just finished 670 | #Note: 671 | #If we registor $self as "setcallback" of 672 | #$apair($id), $apair($i) will callback this 673 | #function with argument id when the flow between the pair finishes. 674 | #i.e. 675 | #If we set: "$apair(13) setcallback $self" somewhere, 676 | #"fin_notify 13 $bytes $fldur $bps" is called when the $apair(13)'s flow is finished. 677 | # 678 | global ns flow_gen flow_fin sim_end 679 | $self instvar logfile 680 | $self instvar group_id 681 | $self instvar actfl 682 | $self instvar apair 683 | 684 | #Here, we re-schedule $apair($pid). 685 | #according to the arrival process. 686 | 687 | $self set actfl [expr $actfl - 1] 688 | 689 | set fin_fid [$apair($pid) set id] 690 | 691 | ###### OUPUT STATISTICS ################# 692 | if { [info exists logfile] } { 693 | #puts $logfile "flow_stats: [$ns now] gid $group_id pid $pid fid $fin_fid bytes $bytes fldur $fldur actfl $actfl bps $bps" 694 | set tmp_pkts [expr $bytes / 1460] 695 | 696 | #puts $logfile "$tmp_pkts $fldur $rttimes" 697 | puts $logfile "$tmp_pkts $fldur $rttimes $group_id $sid" 698 | flush stdout 699 | } 700 | set flow_fin [expr $flow_fin + 1] 701 | if {$flow_fin >= $sim_end} { 702 | finish 703 | } 704 | if {$flow_gen < $sim_end} { 705 | $self schedule $pid ;# re-schedule a pair having pair_id $pid. 706 | } 707 | } 708 | 709 | Agent_Aggr_pair instproc start_notify {} { 710 | #Callback Function 711 | #Note: 712 | #If we registor $self as "setcallback" of 713 | #$apair($id), $apair($i) will callback this 714 | #function with argument id when the flow between the pair finishes. 715 | #i.e. 716 | #If we set: "$apair(13) setcallback $self" somewhere, 717 | #"start_notyf 13" is called when the $apair(13)'s flow is started. 718 | $self instvar actfl; 719 | incr actfl; 720 | } 721 | proc finish {} { 722 | global ns flowlog 723 | global sim_start 724 | #global enableNAM namfile 725 | 726 | #queueTrace 727 | 728 | $ns flush-trace 729 | close $flowlog 730 | 731 | set t [clock seconds] 732 | puts "Simulation Finished!" 733 | puts "Time [expr $t - $sim_start] sec" 734 | #puts "Date [clock format [clock seconds]]" 735 | #if {$enableNAM != 0} { 736 | #close $namfile 737 | #exec nam out.nam & 738 | #} 739 | exit 0 740 | } 741 | -------------------------------------------------------------------------------- /scripts/test-dwrr-2.tcl: -------------------------------------------------------------------------------- 1 | #Experiment setup: service 1, service 2 and service 3 traffic start respectively and have equal weight. 2 | #The total demand of service 3 traffic is restricted to 0.3C (C is link capacity) 3 | 4 | set ns [new Simulator] 5 | 6 | set service1_senders 2 7 | set service2_senders 4 8 | set service3_senders 2 9 | 10 | set K_port 80; #The per-port ECN marking threshold 11 | set K_0 10; #The per-queue ECN marking threshold of the first queue 12 | set K_1 10; #The per-queue ECN marking threshold of the second queue 13 | set K_2 10; #The per-queue ECN marking threshold of the third queue 14 | set W_0 1500; #The weight of the first queue 15 | set W_1 1500; #The weight of the second queue 16 | set W_2 1500; #The weight of the third queue 17 | set marking_scheme 2 18 | 19 | set RTT 0.0001 20 | set DCTCP_g_ 0.0625 21 | set ackRatio 1 22 | set packetSize 1460 23 | set lineRate 10Gb 24 | 25 | set simulationTime 0.03 26 | set throughputSamplingInterval 0.0002 27 | 28 | Agent/TCP set windowInit_ 10 29 | Agent/TCP set ecn_ 1 30 | Agent/TCP set old_ecn_ 1 31 | Agent/TCP set dctcp_ false 32 | Agent/TCP set dctcp_g_ $DCTCP_g_ 33 | Agent/TCP set packetSize_ $packetSize 34 | Agent/TCP set window_ 1256 35 | Agent/TCP set slow_start_restart_ false 36 | Agent/TCP set minrto_ 0.01 ; # minRTO = 10ms 37 | Agent/TCP set windowOption_ 0 38 | Agent/TCP/FullTcp set segsize_ $packetSize 39 | Agent/TCP/FullTcp set segsperack_ $ackRatio; 40 | Agent/TCP/FullTcp set spa_thresh_ 3000; 41 | Agent/TCP/FullTcp set interval_ 0.04 ; #delayed ACK interval = 40ms 42 | 43 | Queue set limit_ 1000 44 | Queue/DWRR set queue_num_ 3 45 | Queue/DWRR set mean_pktsize_ [expr $packetSize + 40] 46 | Queue/DWRR set port_thresh_ $K_port 47 | Queue/DWRR set marking_scheme_ $marking_scheme 48 | Queue/DWRR set estimate_round_alpha_ 0.75 49 | Queue/DWRR set estimate_quantum_alpha_ 0.75 50 | Queue/DWRR set estimate_round_idle_interval_bytes_ 1500 51 | Queue/DWRR set link_capacity_ $lineRate 52 | Queue/DWRR set deque_marking_ false 53 | Queue/DWRR set debug_ true 54 | 55 | set mytracefile [open mytracefile.tr w] 56 | $ns trace-all $mytracefile 57 | set throughputfile [open throughputfile.tr w] 58 | set tot_qlenfile [open tot_qlenfile.tr w] 59 | set qlenfile [open qlenfile.tr w] 60 | 61 | proc finish {} { 62 | global ns mytracefile throughputfile qlenfile tot_qlenfile 63 | $ns flush-trace 64 | close $mytracefile 65 | close $throughputfile 66 | close $qlenfile 67 | close $tot_qlenfile 68 | exit 0 69 | } 70 | 71 | set switch [$ns node] 72 | set receiver [$ns node] 73 | 74 | $ns simplex-link $switch $receiver $lineRate [expr $RTT/4] DWRR 75 | $ns simplex-link $receiver $switch $lineRate [expr $RTT/4] DropTail 76 | 77 | set L [$ns link $switch $receiver] 78 | set q [$L set queue_] 79 | $q set-quantum 0 $W_0 80 | $q set-quantum 1 $W_1 81 | $q set-quantum 2 $W_2 82 | $q set-thresh 0 $K_0 83 | $q set-thresh 1 $K_1 84 | $q set-thresh 2 $K_2 85 | $q attach-total $tot_qlenfile 86 | $q attach-queue $qlenfile 87 | 88 | #Service type 1 senders 89 | for {set i 0} {$i < $service1_senders} {incr i} { 90 | set n1($i) [$ns node] 91 | $ns duplex-link $n1($i) $switch $lineRate [expr $RTT/4] DropTail 92 | set tcp1($i) [new Agent/TCP/FullTcp/Sack] 93 | set sink1($i) [new Agent/TCP/FullTcp/Sack] 94 | $tcp1($i) set serviceid_ 0 95 | $sink1($i) listen 96 | 97 | $ns attach-agent $n1($i) $tcp1($i) 98 | $ns attach-agent $receiver $sink1($i) 99 | $ns connect $tcp1($i) $sink1($i) 100 | 101 | set ftp1($i) [new Application/FTP] 102 | $ftp1($i) attach-agent $tcp1($i) 103 | $ftp1($i) set type_ FTP 104 | $ns at [expr 0.0] "$ftp1($i) start" 105 | } 106 | 107 | #Service type 2 senders 108 | for {set i 0} {$i < $service2_senders} {incr i} { 109 | set n2($i) [$ns node] 110 | $ns duplex-link $n2($i) $switch $lineRate [expr $RTT/4] DropTail 111 | set tcp2($i) [new Agent/TCP/FullTcp/Sack] 112 | set sink2($i) [new Agent/TCP/FullTcp/Sack] 113 | $tcp2($i) set serviceid_ 1 114 | $sink2($i) listen 115 | 116 | $ns attach-agent $n2($i) $tcp2($i) 117 | $ns attach-agent $receiver $sink2($i) 118 | $ns connect $tcp2($i) $sink2($i) 119 | 120 | set ftp2($i) [new Application/FTP] 121 | $ftp2($i) attach-agent $tcp2($i) 122 | $ftp2($i) set type_ FTP 123 | $ns at [expr $simulationTime/3] "$ftp2($i) start" 124 | } 125 | 126 | #Service type 3 senders 127 | for {set i 0} {$i < $service3_senders} {incr i} { 128 | set n3($i) [$ns node] 129 | $ns duplex-link $n3($i) $switch $lineRate [expr $RTT/4] DropTail 130 | set tcp3($i) [new Agent/TCP/FullTcp/Sack] 131 | set sink3($i) [new Agent/TCP/FullTcp/Sack] 132 | $tcp3($i) set serviceid_ 2 133 | $sink3($i) listen 134 | 135 | $ns attach-agent $n3($i) $tcp3($i) 136 | $ns attach-agent $receiver $sink3($i) 137 | $ns connect $tcp3($i) $sink3($i) 138 | 139 | set ftp3($i) [new Application/FTP] 140 | $ftp3($i) attach-agent $tcp3($i) 141 | $ftp3($i) set type_ FTP 142 | 143 | ###Add token bucket rate limiter 144 | set tbf($i) [new TBF] 145 | $tbf($i) set bucket_ 64000 146 | $tbf($i) set rate_ [expr 3000 / $service3_senders]Mbit 147 | $tbf($i) set qlen_ 1000 148 | $ns attach-tbf-agent $n3($i) $tcp3($i) $tbf($i) 149 | 150 | $ns at [expr $simulationTime * 2 / 3] "$ftp3($i) start" 151 | } 152 | 153 | proc record {} { 154 | global ns throughputfile throughputSamplingInterval service1_senders service2_senders service3_senders tcp1 sink1 tcp2 sink2 tcp3 sink3 155 | 156 | #Get the current time 157 | set now [$ns now] 158 | 159 | #Initialize the output string 160 | set str $now 161 | append str ", " 162 | 163 | set bw1 0 164 | for {set i 0} {$i < $service1_senders} {incr i} { 165 | set bytes [$sink1($i) set bytes_] 166 | set bw1 [expr $bw1 + $bytes] 167 | $sink1($i) set bytes_ 0 168 | } 169 | 170 | append str [expr int($bw1 / $throughputSamplingInterval * 8 / 1000000)]; #throughput in Mbps 171 | append str ", " 172 | 173 | set bw2 0 174 | for {set i 0} {$i < $service2_senders} {incr i} { 175 | set bytes [$sink2($i) set bytes_] 176 | set bw2 [expr $bw2 + $bytes] 177 | $sink2($i) set bytes_ 0 178 | } 179 | 180 | append str [expr int($bw2 / $throughputSamplingInterval * 8 / 1000000)]; #throughput in Mbps 181 | append str ", " 182 | 183 | set bw3 0 184 | for {set i 0} {$i < $service3_senders} {incr i} { 185 | set bytes [$sink3($i) set bytes_] 186 | set bw3 [expr $bw3 + $bytes] 187 | $sink3($i) set bytes_ 0 188 | } 189 | 190 | append str [expr int($bw3 / $throughputSamplingInterval * 8 / 1000000)]; #throughput in Mbps 191 | 192 | puts $throughputfile $str 193 | #Set next callback time 194 | $ns at [expr $now + $throughputSamplingInterval] "record" 195 | 196 | } 197 | 198 | $ns at 0.0 "record" 199 | $ns at [expr $simulationTime] "finish" 200 | $ns run 201 | -------------------------------------------------------------------------------- /scripts/test-dwrr.tcl: -------------------------------------------------------------------------------- 1 | set ns [new Simulator] 2 | 3 | set service1_senders 8 4 | set service2_senders 2 5 | set K_port 80; #The per-port ECN marking threshold 6 | set K_0 4; #The per-queue ECN marking threshold of the first queue 7 | set K_1 16; #The per-queue ECN marking threshold of the second queue 8 | set W_0 1500; #The quantum (weight) of the first queue 9 | set W_1 6000; #The quantum (weight) of the second queue 10 | set marking_scheme 2 11 | 12 | set RTT 0.0001 13 | set DCTCP_g_ 0.0625 14 | set ackRatio 1 15 | set packetSize 1460 16 | set lineRate 10Gb 17 | 18 | set simulationTime 0.02 19 | set throughputSamplingInterval 0.0002 20 | 21 | Agent/TCP set windowInit_ 10 22 | Agent/TCP set ecn_ 1 23 | Agent/TCP set old_ecn_ 1 24 | Agent/TCP set dctcp_ false 25 | Agent/TCP set dctcp_g_ $DCTCP_g_ 26 | Agent/TCP set packetSize_ $packetSize 27 | Agent/TCP set window_ 1256 28 | Agent/TCP set slow_start_restart_ false 29 | Agent/TCP set minrto_ 0.01 ; # minRTO = 10ms 30 | Agent/TCP set windowOption_ 0 31 | Agent/TCP/FullTcp set segsize_ $packetSize 32 | Agent/TCP/FullTcp set segsperack_ $ackRatio; 33 | Agent/TCP/FullTcp set spa_thresh_ 3000; 34 | Agent/TCP/FullTcp set interval_ 0.04 ; #delayed ACK interval = 40ms 35 | 36 | Queue set limit_ 1000 37 | 38 | Queue/DWRR set queue_num_ 2 39 | Queue/DWRR set mean_pktsize_ [expr $packetSize + 40] 40 | Queue/DWRR set port_thresh_ $K_port 41 | Queue/DWRR set marking_scheme_ $marking_scheme 42 | Queue/DWRR set estimate_round_alpha_ 0.75 43 | Queue/DWRR set estimate_round_idle_interval_bytes_ 1500 44 | Queue/DWRR set link_capacity_ $lineRate 45 | Queue/DWRR set deque_marking_ false 46 | Queue/DWRR set debug_ true 47 | 48 | Queue/RED set bytes_ false 49 | Queue/RED set queue_in_bytes_ true 50 | Queue/RED set mean_pktsize_ [expr $packetSize + 40] 51 | Queue/RED set setbit_ true 52 | Queue/RED set gentle_ false 53 | Queue/RED set q_weight_ 1.0 54 | Queue/RED set mark_p_ 1.0 55 | Queue/RED set thresh_ $K_port 56 | Queue/RED set maxthresh_ $K_port 57 | 58 | set mytracefile [open mytracefile.tr w] 59 | $ns trace-all $mytracefile 60 | set throughputfile [open throughputfile.tr w] 61 | set tot_qlenfile [open tot_qlenfile.tr w] 62 | set qlenfile [open qlenfile.tr w] 63 | 64 | proc finish {} { 65 | global ns mytracefile throughputfile qlenfile tot_qlenfile 66 | $ns flush-trace 67 | close $mytracefile 68 | close $throughputfile 69 | close $qlenfile 70 | close $tot_qlenfile 71 | exit 0 72 | } 73 | 74 | set switch [$ns node] 75 | set receiver [$ns node] 76 | 77 | $ns simplex-link $switch $receiver $lineRate [expr $RTT/4] DWRR 78 | $ns simplex-link $receiver $switch $lineRate [expr $RTT/4] DropTail 79 | 80 | set L [$ns link $switch $receiver] 81 | set q [$L set queue_] 82 | $q set-quantum 0 $W_0 83 | $q set-quantum 1 $W_1 84 | $q set-thresh 0 $K_0 85 | $q set-thresh 1 $K_1 86 | $q attach-total $tot_qlenfile 87 | $q attach-queue $qlenfile 88 | 89 | #Service type 1 senders 90 | for {set i 0} {$i < $service1_senders} {incr i} { 91 | set n1($i) [$ns node] 92 | $ns duplex-link $n1($i) $switch $lineRate [expr $RTT/4] RED 93 | set tcp1($i) [new Agent/TCP/FullTcp/Sack] 94 | set sink1($i) [new Agent/TCP/FullTcp/Sack] 95 | $tcp1($i) set serviceid_ 0 96 | $sink1($i) listen 97 | 98 | $ns attach-agent $n1($i) $tcp1($i) 99 | $ns attach-agent $receiver $sink1($i) 100 | $ns connect $tcp1($i) $sink1($i) 101 | 102 | set ftp1($i) [new Application/FTP] 103 | $ftp1($i) attach-agent $tcp1($i) 104 | $ftp1($i) set type_ FTP 105 | $ns at [expr 0.0] "$ftp1($i) start" 106 | } 107 | 108 | #Service type 2 senders 109 | for {set i 0} {$i < $service2_senders} {incr i} { 110 | set n2($i) [$ns node] 111 | $ns duplex-link $n2($i) $switch $lineRate [expr $RTT/4] RED 112 | set tcp2($i) [new Agent/TCP/FullTcp/Sack] 113 | set sink2($i) [new Agent/TCP/FullTcp/Sack] 114 | $tcp2($i) set serviceid_ 1 115 | $sink2($i) listen 116 | 117 | $ns attach-agent $n2($i) $tcp2($i) 118 | $ns attach-agent $receiver $sink2($i) 119 | $ns connect $tcp2($i) $sink2($i) 120 | 121 | set ftp2($i) [new Application/FTP] 122 | $ftp2($i) attach-agent $tcp2($i) 123 | $ftp2($i) set type_ FTP 124 | $ns at [expr $simulationTime/2] "$ftp2($i) start" 125 | } 126 | 127 | proc record {} { 128 | global ns throughputfile throughputSamplingInterval service1_senders service2_senders tcp1 sink1 tcp2 sink2 129 | 130 | #Get the current time 131 | set now [$ns now] 132 | 133 | #Initialize the output string 134 | set str $now 135 | append str ", " 136 | 137 | set bw1 0 138 | for {set i 0} {$i < $service1_senders} {incr i} { 139 | set bytes [$sink1($i) set bytes_] 140 | set bw1 [expr $bw1 + $bytes] 141 | $sink1($i) set bytes_ 0 142 | } 143 | 144 | append str [expr int($bw1 / $throughputSamplingInterval * 8 / 1000000)]; #throughput in Mbps 145 | append str ", " 146 | 147 | set bw2 0 148 | for {set i 0} {$i < $service2_senders} {incr i} { 149 | set bytes [$sink2($i) set bytes_] 150 | set bw2 [expr $bw2 + $bytes] 151 | $sink2($i) set bytes_ 0 152 | } 153 | 154 | append str [expr int($bw2 / $throughputSamplingInterval * 8 / 1000000)]; #throughput in Mbps 155 | puts $throughputfile $str 156 | 157 | #Set next callback time 158 | $ns at [expr $now + $throughputSamplingInterval] "record" 159 | } 160 | 161 | $ns at 0.0 "record" 162 | $ns at [expr $simulationTime] "finish" 163 | $ns run 164 | -------------------------------------------------------------------------------- /scripts/test-wrr-2.tcl: -------------------------------------------------------------------------------- 1 | #Experiment setup: service 1, service 2 and service 3 traffic start respectively and have equal weight. 2 | #The total demand of service 3 traffic is restricted to 0.3C (C is link capacity) 3 | 4 | set ns [new Simulator] 5 | 6 | set service1_senders 2 7 | set service2_senders 4 8 | set service3_senders 2 9 | 10 | set K_port 80; #The per-port ECN marking threshold 11 | set K_0 10; #The per-queue ECN marking threshold of the first queue 12 | set K_1 10; #The per-queue ECN marking threshold of the second queue 13 | set K_2 10; #The per-queue ECN marking threshold of the third queue 14 | set W_0 1500; #The quantum/weight of the first queue 15 | set W_1 1500; #The quantum/weightof the second queue 16 | set W_2 1500; #The quantum/weight of the third queue 17 | set marking_scheme 2 18 | 19 | set RTT 0.0001 20 | set DCTCP_g_ 0.0625 21 | set ackRatio 1 22 | set packetSize 1460 23 | set lineRate 10Gb 24 | 25 | set simulationTime 0.03 26 | set throughputSamplingInterval 0.0002 27 | 28 | Agent/TCP set windowInit_ 10 29 | Agent/TCP set ecn_ 1 30 | Agent/TCP set old_ecn_ 1 31 | Agent/TCP set dctcp_ false 32 | Agent/TCP set dctcp_g_ $DCTCP_g_ 33 | Agent/TCP set packetSize_ $packetSize 34 | Agent/TCP set window_ 1256 35 | Agent/TCP set slow_start_restart_ false 36 | Agent/TCP set minrto_ 0.01 ; # minRTO = 10ms 37 | Agent/TCP set windowOption_ 0 38 | Agent/TCP/FullTcp set segsize_ $packetSize 39 | Agent/TCP/FullTcp set segsperack_ $ackRatio; 40 | Agent/TCP/FullTcp set spa_thresh_ 3000; 41 | Agent/TCP/FullTcp set interval_ 0.04 ; #delayed ACK interval = 40ms 42 | 43 | Queue set limit_ 1000 44 | Queue/WRR set queue_num_ 3 45 | Queue/WRR set mean_pktsize_ [expr $packetSize + 40] 46 | Queue/WRR set port_thresh_ $K_port 47 | Queue/WRR set marking_scheme_ $marking_scheme 48 | Queue/WRR set estimate_round_alpha_ 0.75 49 | Queue/WRR set estimate_round_idle_interval_bytes_ [expr $packetSize + 40] 50 | Queue/WRR set link_capacity_ $lineRate 51 | Queue/WRR set deque_marking_ false 52 | Queue/WRR set debug_ true 53 | 54 | set mytracefile [open mytracefile.tr w] 55 | $ns trace-all $mytracefile 56 | set throughputfile [open throughputfile.tr w] 57 | set tot_qlenfile [open tot_qlenfile.tr w] 58 | set qlenfile [open qlenfile.tr w] 59 | 60 | proc finish {} { 61 | global ns mytracefile throughputfile qlenfile tot_qlenfile 62 | $ns flush-trace 63 | close $mytracefile 64 | close $throughputfile 65 | close $qlenfile 66 | close $tot_qlenfile 67 | exit 0 68 | } 69 | 70 | set switch [$ns node] 71 | set receiver [$ns node] 72 | 73 | $ns simplex-link $switch $receiver $lineRate [expr $RTT/4] WRR 74 | $ns simplex-link $receiver $switch $lineRate [expr $RTT/4] DropTail 75 | 76 | set L [$ns link $switch $receiver] 77 | set q [$L set queue_] 78 | $q set-quantum 0 $W_0 79 | $q set-quantum 1 $W_1 80 | $q set-quantum 2 $W_2 81 | $q set-thresh 0 $K_0 82 | $q set-thresh 1 $K_1 83 | $q set-thresh 2 $K_2 84 | $q attach-total $tot_qlenfile 85 | $q attach-queue $qlenfile 86 | 87 | #Service type 1 senders 88 | for {set i 0} {$i < $service1_senders} {incr i} { 89 | set n1($i) [$ns node] 90 | $ns duplex-link $n1($i) $switch $lineRate [expr $RTT/4] DropTail 91 | set tcp1($i) [new Agent/TCP/FullTcp/Sack] 92 | set sink1($i) [new Agent/TCP/FullTcp/Sack] 93 | $tcp1($i) set serviceid_ 0 94 | $sink1($i) listen 95 | 96 | $ns attach-agent $n1($i) $tcp1($i) 97 | $ns attach-agent $receiver $sink1($i) 98 | $ns connect $tcp1($i) $sink1($i) 99 | 100 | set ftp1($i) [new Application/FTP] 101 | $ftp1($i) attach-agent $tcp1($i) 102 | $ftp1($i) set type_ FTP 103 | $ns at [expr 0.0] "$ftp1($i) start" 104 | } 105 | 106 | #Service type 2 senders 107 | for {set i 0} {$i < $service2_senders} {incr i} { 108 | set n2($i) [$ns node] 109 | $ns duplex-link $n2($i) $switch $lineRate [expr $RTT/4] DropTail 110 | set tcp2($i) [new Agent/TCP/FullTcp/Sack] 111 | set sink2($i) [new Agent/TCP/FullTcp/Sack] 112 | $tcp2($i) set serviceid_ 1 113 | $sink2($i) listen 114 | 115 | $ns attach-agent $n2($i) $tcp2($i) 116 | $ns attach-agent $receiver $sink2($i) 117 | $ns connect $tcp2($i) $sink2($i) 118 | 119 | set ftp2($i) [new Application/FTP] 120 | $ftp2($i) attach-agent $tcp2($i) 121 | $ftp2($i) set type_ FTP 122 | $ns at [expr $simulationTime / 3] "$ftp2($i) start" 123 | } 124 | 125 | #Service type 3 senders 126 | for {set i 0} {$i < $service3_senders} {incr i} { 127 | set n3($i) [$ns node] 128 | $ns duplex-link $n3($i) $switch $lineRate [expr $RTT/4] DropTail 129 | set tcp3($i) [new Agent/TCP/FullTcp/Sack] 130 | set sink3($i) [new Agent/TCP/FullTcp/Sack] 131 | $tcp3($i) set serviceid_ 2 132 | $sink3($i) listen 133 | 134 | $ns attach-agent $n3($i) $tcp3($i) 135 | $ns attach-agent $receiver $sink3($i) 136 | $ns connect $tcp3($i) $sink3($i) 137 | 138 | set ftp3($i) [new Application/FTP] 139 | $ftp3($i) attach-agent $tcp3($i) 140 | $ftp3($i) set type_ FTP 141 | 142 | ###Add token bucket rate limiter 143 | set tbf($i) [new TBF] 144 | $tbf($i) set bucket_ 64000 145 | $tbf($i) set rate_ [expr 3000 / $service3_senders]Mbit 146 | $tbf($i) set qlen_ 1000 147 | $ns attach-tbf-agent $n3($i) $tcp3($i) $tbf($i) 148 | 149 | $ns at [expr $simulationTime * 2 / 3] "$ftp3($i) start" 150 | } 151 | 152 | proc record {} { 153 | global ns throughputfile throughputSamplingInterval service1_senders service2_senders service3_senders tcp1 sink1 tcp2 sink2 tcp3 sink3 154 | 155 | #Get the current time 156 | set now [$ns now] 157 | 158 | #Initialize the output string 159 | set str $now 160 | append str ", " 161 | 162 | set bw1 0 163 | for {set i 0} {$i < $service1_senders} {incr i} { 164 | set bytes [$sink1($i) set bytes_] 165 | set bw1 [expr $bw1 + $bytes] 166 | $sink1($i) set bytes_ 0 167 | } 168 | 169 | append str [expr int($bw1 / $throughputSamplingInterval * 8 / 1000000)]; #throughput in Mbps 170 | append str ", " 171 | 172 | set bw2 0 173 | for {set i 0} {$i < $service2_senders} {incr i} { 174 | set bytes [$sink2($i) set bytes_] 175 | set bw2 [expr $bw2 + $bytes] 176 | $sink2($i) set bytes_ 0 177 | } 178 | 179 | append str [expr int($bw2 / $throughputSamplingInterval * 8 / 1000000)]; #throughput in Mbps 180 | append str ", " 181 | 182 | set bw3 0 183 | for {set i 0} {$i < $service3_senders} {incr i} { 184 | set bytes [$sink3($i) set bytes_] 185 | set bw3 [expr $bw3 + $bytes] 186 | $sink3($i) set bytes_ 0 187 | } 188 | 189 | append str [expr int($bw3 / $throughputSamplingInterval * 8 / 1000000)]; #throughput in Mbps 190 | 191 | puts $throughputfile $str 192 | #Set next callback time 193 | $ns at [expr $now + $throughputSamplingInterval] "record" 194 | 195 | } 196 | 197 | $ns at 0.0 "record" 198 | $ns at [expr $simulationTime] "finish" 199 | $ns run 200 | -------------------------------------------------------------------------------- /scripts/test-wrr.tcl: -------------------------------------------------------------------------------- 1 | set ns [new Simulator] 2 | 3 | set service1_senders 8 4 | set service2_senders 2 5 | set K_port 80; #The per-port ECN marking threshold 6 | set K_0 80; #The per-queue ECN marking threshold of the first queue 7 | set K_1 80; #The per-queue ECN marking threshold of the second queue 8 | set W_0 1500; #The quantum/weight of the first queue 9 | set W_1 3000; #The quantum/weight of the second queue 10 | set marking_scheme 2 11 | 12 | set RTT 0.0001 13 | set DCTCP_g_ 0.0625 14 | set ackRatio 1 15 | set packetSize 1460 16 | set lineRate 10Gb 17 | 18 | set simulationTime 0.02 19 | set throughputSamplingInterval 0.0002 20 | 21 | Agent/TCP set windowInit_ 10 22 | Agent/TCP set ecn_ 1 23 | Agent/TCP set old_ecn_ 1 24 | Agent/TCP set dctcp_ false 25 | Agent/TCP set dctcp_g_ $DCTCP_g_ 26 | Agent/TCP set packetSize_ $packetSize 27 | Agent/TCP set window_ 1256 28 | Agent/TCP set slow_start_restart_ false 29 | Agent/TCP set minrto_ 0.01 ; # minRTO = 10ms 30 | Agent/TCP set windowOption_ 0 31 | Agent/TCP/FullTcp set segsize_ $packetSize 32 | Agent/TCP/FullTcp set segsperack_ $ackRatio; 33 | Agent/TCP/FullTcp set spa_thresh_ 3000; 34 | Agent/TCP/FullTcp set interval_ 0.04 ; #delayed ACK interval = 40ms 35 | 36 | Queue set limit_ 1000 37 | Queue/WRR set queue_num_ 2 38 | Queue/WRR set mean_pktsize_ [expr $packetSize + 40] 39 | Queue/WRR set port_thresh_ $K_port 40 | Queue/WRR set marking_scheme_ $marking_scheme 41 | Queue/WRR set estimate_round_alpha_ 0.75 42 | Queue/WRR set estimate_round_idle_interval_bytes_ [expr $packetSize + 40] 43 | Queue/WRR set link_capacity_ $lineRate 44 | Queue/WRR set deque_marking_ false 45 | Queue/WRR set debug_ true 46 | 47 | set mytracefile [open mytracefile.tr w] 48 | $ns trace-all $mytracefile 49 | set throughputfile [open throughputfile.tr w] 50 | set tot_qlenfile [open tot_qlenfile.tr w] 51 | set qlenfile [open qlenfile.tr w] 52 | 53 | proc finish {} { 54 | global ns mytracefile throughputfile qlenfile tot_qlenfile 55 | $ns flush-trace 56 | close $mytracefile 57 | close $throughputfile 58 | close $qlenfile 59 | close $tot_qlenfile 60 | exit 0 61 | } 62 | 63 | set switch [$ns node] 64 | set receiver [$ns node] 65 | 66 | $ns simplex-link $switch $receiver $lineRate [expr $RTT/4] WRR 67 | $ns simplex-link $receiver $switch $lineRate [expr $RTT/4] DropTail 68 | 69 | set L [$ns link $switch $receiver] 70 | set q [$L set queue_] 71 | $q set-quantum 0 $W_0 72 | $q set-quantum 1 $W_1 73 | $q set-thresh 0 $K_0 74 | $q set-thresh 1 $K_1 75 | $q attach-total $tot_qlenfile 76 | $q attach-queue $qlenfile 77 | 78 | #Service type 1 senders 79 | for {set i 0} {$i < $service1_senders} {incr i} { 80 | set n1($i) [$ns node] 81 | $ns duplex-link $n1($i) $switch $lineRate [expr $RTT/4] DropTail 82 | set tcp1($i) [new Agent/TCP/FullTcp/Sack] 83 | set sink1($i) [new Agent/TCP/FullTcp/Sack] 84 | $tcp1($i) set serviceid_ 0 85 | $sink1($i) listen 86 | 87 | $ns attach-agent $n1($i) $tcp1($i) 88 | $ns attach-agent $receiver $sink1($i) 89 | $ns connect $tcp1($i) $sink1($i) 90 | 91 | set ftp1($i) [new Application/FTP] 92 | $ftp1($i) attach-agent $tcp1($i) 93 | $ftp1($i) set type_ FTP 94 | $ns at [expr 0.0] "$ftp1($i) start" 95 | } 96 | 97 | #Service type 2 senders 98 | for {set i 0} {$i<$service2_senders} {incr i} { 99 | set n2($i) [$ns node] 100 | $ns duplex-link $n2($i) $switch $lineRate [expr $RTT/4] DropTail 101 | set tcp2($i) [new Agent/TCP/FullTcp/Sack] 102 | set sink2($i) [new Agent/TCP/FullTcp/Sack] 103 | $tcp2($i) set serviceid_ 1 104 | $sink2($i) listen 105 | 106 | $ns attach-agent $n2($i) $tcp2($i) 107 | $ns attach-agent $receiver $sink2($i) 108 | $ns connect $tcp2($i) $sink2($i) 109 | 110 | set ftp2($i) [new Application/FTP] 111 | $ftp2($i) attach-agent $tcp2($i) 112 | $ftp2($i) set type_ FTP 113 | $ns at [expr $simulationTime / 2] "$ftp2($i) start" 114 | } 115 | 116 | proc record {} { 117 | global ns throughputfile throughputSamplingInterval service1_senders service2_senders tcp1 sink1 tcp2 sink2 118 | 119 | #Get the current time 120 | set now [$ns now] 121 | 122 | #Initialize the output string 123 | set str $now 124 | append str ", " 125 | 126 | set bw1 0 127 | for {set i 0} {$i < $service1_senders} {incr i} { 128 | set bytes [$sink1($i) set bytes_] 129 | set bw1 [expr $bw1 + $bytes] 130 | $sink1($i) set bytes_ 0 131 | } 132 | 133 | append str [expr int($bw1 / $throughputSamplingInterval * 8 / 1000000)]; #throughput in Mbps 134 | append str ", " 135 | 136 | set bw2 0 137 | for {set i 0} {$i < $service2_senders} {incr i} { 138 | set bytes [$sink2($i) set bytes_] 139 | set bw2 [expr $bw2 + $bytes] 140 | $sink2($i) set bytes_ 0 141 | } 142 | 143 | append str [expr int($bw2 / $throughputSamplingInterval * 8 / 1000000)]; #throughput in Mbps 144 | puts $throughputfile $str 145 | 146 | #Set next callback time 147 | $ns at [expr $now + $throughputSamplingInterval] "record" 148 | 149 | } 150 | 151 | $ns at 0.0 "record" 152 | $ns at [expr $simulationTime] "finish" 153 | $ns run 154 | --------------------------------------------------------------------------------