1 ///////////////////////////////////////////////////////////////////////////////
3 // Multiplexer with EPD/PPD and CLP thresholds
5 // MuxCLP mux: NINP=<int>, // number of inputs
6 // BUFF=<int>, // buffer size (cells)
7 // {MAXVCI=<int>,} // max. VCI number (default NINP)
8 // EPDTHRESH=<int>, // when to not accept new frames (EPD-Thresh)
9 // CLP1THRESH=<int>, // when to discard CLP=1 cells
10 // {EPD_CLP1=<bool>,} // perform EPD/PPD for CLP=1 cells ? standard=0
11 // {DFBA=<bool>,} // perform DFBA?, standard 0, to perform DFBA,
12 // // EPD_CLP1 has to be set to 1, see below
13 // {FAIR_CLP0=<bool>,} // fair discarding of CLP=0 cells, see below
14 // {FBA0=<bool>,} // perform FBA, standard 0, see below
15 // {PERFORM_RED1=<bool>, // perform RED, standard 0, additional
16 // ...} // RED arguments, see source
17 // {DELIVER_PT1=<bool>,} // deliver pt=1 cells regardless of thresholds
18 // // and EPD? standard=0
21 // Commands: see Multiplexer (mux.c)
22 // ->ResetStat: Reset the statistics for CLR, CLR0, and CLR1
23 // ->CLR(i): cell loss ratio of all cells of vc i
24 // ->CLR0(i): cell loss ratio of CLP=0 cells of vc i
25 // ->CLR0(i): cell loss ratio of CLP=1 cells of vc i
28 // This mux has evolved from clpmux and ewsxmux.
29 // FAIR_CLP0: discarding of CLP=0, if buffer is above clp1thresh
30 // and the VCI queue (regardless of CLP) is larger than 80% of its
31 // fair share, EPD is performed (no discarding of partial frames)
32 // may not be used together with FBA0 and DFBA
33 // FBA0: as FAIR_CLP0, but in this case only CLP=0 cells are considered
34 // for the VCI queue length
35 // may not be used together with FAIR_CLP0
36 // DFBA: may not be used together with FAIR_CLP0
38 ///////////////////////////////////////////////////////////////////////////////
42 CONSTRUCTOR(MuxCLP
, muxCLP
);
43 USERCLASS("MuxCLP", MuxCLP
);
45 // read additional (compared to mux) parameters
46 void muxCLP::addpars(void)
52 epdThresh
= read_int("EPDTHRESH");
54 syntax0("invalid EPDTHRESH");
57 clp1Thresh
= read_int("CLP1THRESH");
59 syntax0("invalid CLP1THRESH");
62 // boolean, should we perform EPD/PPD for CLP=1 packets
63 if(test_word("EPD_CLP1"))
65 epdClp1
= read_int("EPD_CLP1");
66 if (epdClp1
< 0 || epdClp1
>1)
67 syntax0("EPD_CLP1 must be 0 or 1");
76 performDFBA
= read_int("DFBA");
77 if (performDFBA
< 0 || performDFBA
>1)
78 syntax0("DFBA must be 0 or 1");
84 if(performDFBA
&& !epdClp1
)
85 syntax0("to perform DFBA, EPD_CLP1 must be set to 1");
87 // boolean, discard CLP0 if above trheshold
88 if(test_word("FAIR_CLP0"))
90 fairClp0
= read_int("FAIR_CLP0");
91 if (fairClp0
< 0 || fairClp0
>1)
92 syntax0("FAIR_CLP0 must be 0 or 1");
98 // boolean, discard CLP0 if above trheshold
101 fba0
= read_int("FBA0");
102 if (fba0
< 0 || fba0
>1)
103 syntax0("FBA0 must be 0 or 1");
110 syntax0("to perform FBA0, FAIR_CLP0 must be set to 0 (or vice versa)");
112 if(performDFBA
&& fairClp0
)
113 syntax0("to perform DFBA, FAIR_CLP0 must be set to 0");
116 // read in RED parameter
118 if(test_word("PERFORM_RED1"))
120 perform_RED1
= read_int("PERFORM_RED1");
129 red1
.th_l
= read_int("RED1_TH_LOW"); // lower threshold for performing RED
131 syntax0("RED1_TH_LOW must be >= 0");
132 else if(red1
.th_l
>= q
.getmax())
133 syntax0("RED1_TH_LOW must be < BUFF");
136 red1
.th_h
= read_int("RED1_TH_HIGH"); // lower threshold for performing RED
137 if(red1
.th_h
<= red1
.th_l
)
138 syntax0("RED1_TH_HIGH be > RED1_TH_LOW");
139 else if(red1
.th_h
> q
.getmax())
140 syntax0("RED1_TH_HIGH must be <= BUFF");
143 red1
.pmax
= read_double("RED1_PMAX"); // lower threshold for performing RED
144 if(red1
.pmax
< 0 || red1
.pmax
> 1)
145 syntax0("RED1_PMAX must be in [0,1]");
148 red1
.pstart
= read_double("RED1_PSTART"); // lower threshold for performing RED
149 if(red1
.pstart
< 0 || red1
.pstart
> 1)
150 syntax0("RED1_PSTART must be in [0,1]");
153 if(test_word("RED1_USEAVERAGE"))
155 red1
.useaverage
= read_int("RED1_USEAVERAGE"); // lower threshold for performing RED
156 if(red1
.useaverage
< 0 || red1
.useaverage
> 1)
157 syntax0("RED1_USEAVERAGE must be in [0,1]");
163 if(test_word("RED1_WQ"))
165 red1
.w_q
= read_double("RED1_WQ");
166 if(red1
.w_q
<= 0 || red1
.w_q
> 1)
167 syntax0("RED1_WQ must be in (0,1]");
173 // boolean, should we always deliver pt=1 cells (if global buffer allows)
174 if(test_word("DELIVER_PT1"))
176 deliverPt1
= read_int("DELIVER_PT1");
177 if ( deliverPt1
< 0 || deliverPt1
>1)
178 syntax0("DELIVER_PT11 must be 0 or 1");
184 // the connection parameters
185 CHECK(cpar
= new ClpMuxConnParam
* [max_vci
]);
186 for (i
= 0; i
< max_vci
; ++i
)
188 CHECK(cpar
[i
] = new ClpMuxConnParam(i
));
189 cpar
[i
]->maxqlen_epd
= q
.getmax();
190 cpar
[i
]->maxqlen1_epd
= q
.getmax();
196 ///////////////////////////////////////////////////////////////////////////////
198 // a cell has arrived
199 ///////////////////////////////////////////////////////////////////////////////
200 void muxCLP::late(event
*)
205 // process all arrivals in random order
206 n
= inp_ptr
- inp_buff
;
210 p
= inp_buff
+ (my_rand() % n
);
214 if (typequery(p
->pdata
, AAL5CellType
))
219 vc
= (pc
= (aal5Cell
*) p
->pdata
)->vci
;
221 if (vc
< 0 || vc
>= max_vci
)
222 errm1s2d("%s: AAL5 cell with illegal VCI=%d received on"
223 " input %d", name
, vc
, p
->inp
+ 1);
225 cpar
[vc
]->received
++;
227 cpar
[vc
]->received0
++;
229 // at the beginning of a burst: check whether to accept burst
230 if (cpar
[vc
]->vciFirst
)
232 cpar
[vc
]->vciOK
= TRUE
;
233 cpar
[vc
]->vciFirst
= FALSE
;
234 if (q
.getlen() >= epdThresh
|| cpar
[vc
]->qlen
>= cpar
[vc
]->maxqlen_epd
)
235 cpar
[vc
]->vciOK
= FALSE
;
237 // discard clp1-frames if queue is above the VCI threshold
238 if (pc
->clp
== 1 && cpar
[vc
]->qlen
>= cpar
[vc
]->maxqlen1_epd
)
239 cpar
[vc
]->vciOK
= FALSE
;
242 // discard clp1-frames if queue is above the threshold
243 if (epdClp1
&& pc
->clp
== 1 && q
.getlen() >= clp1Thresh
)
244 cpar
[vc
]->vciOK
= FALSE
;
246 if(perform_RED1
&& pc
->clp
== 1)
249 drop
= red1
.Update(q
.q_len
);
251 cpar
[vc
]->vciOK
= FALSE
;
254 // discard clp0-frames if this vc uses more than its fair
256 // all cells (including clp=1 cells are considered)
257 // this is the difference to fba0
258 if (fairClp0
&& pc
->clp
== 0 && q
.getlen() >= clp1Thresh
) // FBA with Z=0.8
260 if( cpar
[vc
]->qlen
* (max_vci
-1) / (double)q
.getlen() >
261 0.8*(epdThresh
)/(double)(q
.getlen())
263 cpar
[vc
]->vciOK
= FALSE
;
267 // FBA with Z=0.8 for CLP=0 cells
268 // the buffer between clp1Thresh and epdThresh is considered
269 // to be shared fair only, this is the difference to fairClp0
270 if (fba0
&& pc
->clp
== 0 && q
.getlen() >= clp1Thresh
)
272 if( cpar
[vc
]->qlen0
* (max_vci
-1) / (double)q
.getlen() >
273 0.8*(epdThresh
-clp1Thresh
)/(double)(q
.getlen()-clp1Thresh
))
275 cpar
[vc
]->vciOK
= FALSE
;
280 // perform DFBA, not that DFBA uses per-VC weights
281 if(performDFBA
&&pc
->clp
== 0 && q
.getlen() >= clp1Thresh
&&
282 q
.getlen() < epdThresh
)
284 if(cpar
[vc
]->qlen
> (int)(q
.getlen() / (double)(max_vci
-1)))
287 double X
= q
.getlen();
288 double Xi
= cpar
[vc
]->qlen
;
289 double Z
= 1.0; //1.0 - (1.0/max_vci);
291 //double rat = 1.0/max_vci;
292 double rat
= cpar
[vc
]->SCR_ratio
;
293 double L
= clp1Thresh
;
294 double H
= epdThresh
;
296 p
= Z
*(a
*(Xi
-X
*rat
)/(X
*(1.0-rat
)) + (1.0-a
)*(X
-L
)/(H
-L
));
297 //printf("vc=%d, X=%f, Xi=%f, L=%f, H=%f, rat=%f\n",vc,X,Xi, L,H,rat);
298 //printf("vc=%d, p=%f\n",vc,p);
299 // discard frame with the probability
301 cpar
[vc
]->vciOK
= FALSE
;
305 } // if DFBA is to be performed
307 } // if first cell of a frame
309 if (pc
->pt
== 1) // next cell will be first cell
310 cpar
[vc
]->vciFirst
= TRUE
;
312 // if no EPD for CLP=1 cells, then discard cells if above threshold
313 if(!epdClp1
&& pc
->clp
== 1 && q
.getlen() > clp1Thresh
)
318 // Test Mue 18.02.2000 if (cpar[vc]->vciOK)
319 // accept if VC is ok or if a pt=1 cells (if option has been choosen)
320 if(cpar
[vc
]->vciOK
|| (pc
->pt
== 1 && deliverPt1
))
322 if ( !q
.enqueue(pc
)) // buffer overflow
330 cpar
[vc
]->vciOK
= FALSE
; // drop the rest of the burst
332 else // succesful served
354 if (q
.enqueue(p
->pdata
) == FALSE
)
363 alarme( &std_evt
, 1);
368 ///////////////////////////////////////////////////////////////////////////////
370 // serve one data item
371 ///////////////////////////////////////////////////////////////////////////////
372 void muxCLP::early(event
*)
375 pc
= (cell
*) q
.dequeue();
386 ///////////////////////////////////////////////////////////////////////////////
388 ///////////////////////////////////////////////////////////////////////////////
389 void muxCLP::ResetStatVC(int vc
)
391 if (vc
< 0 || vc
>= max_vci
)
392 errm1s1d("%s: ResetVC with illegal VC=%d called", name
, vc
);
394 cpar
[vc
]->received
= 0;
396 cpar
[vc
]->received0
= 0;
398 cpar
[vc
]->served
= 0;
403 ///////////////////////////////////////////////////////////////////////////////
405 ///////////////////////////////////////////////////////////////////////////////
406 int muxCLP::command(char *s
,tok_typ
*pv
)
411 if (baseclass::command(s
, pv
))
414 if(!strcmp(s
, "SetCLP1threshEPD")) // VCI-specific CLP-1-EPD threshold
418 if(vc
< 0 || vc
>= max_vci
)
419 syntax1s1d("%s: invalid VCI used: %d", name
, vc
);
422 cpar
[vc
]->maxqlen1_epd
= read_int(NULL
);
423 if ( cpar
[vc
]->maxqlen1_epd
< 1)
424 syntax1s("%s: VCI-specific CLP1-TRHESHOLD must be > 0", name
);
430 else if(!strcmp(s
, "SetCLP0threshEPD")) // VCI-specific CLP-1-EPD threshold
434 if(vc
< 0 || vc
>= max_vci
)
435 syntax1s1d("%s: invalid VCI used: %d", name
, vc
);
438 cpar
[vc
]->maxqlen_epd
= read_int(NULL
);
439 if ( cpar
[vc
]->maxqlen_epd
< 1)
440 syntax1s("%s: VCI-specific CLP0-TRHESHOLD must be > 0", name
);
446 else if(!strcmp(s
, "SetSCR"))
450 if(vc
< 0 || vc
>= max_vci
)
451 syntax1s1d("%s: invalid VCI used: %d", name
, vc
);
453 double rate
= read_double(NULL
);
455 syntax1s("%s: SCR must be > 0", name
);
457 cpar
[vc
]->SCR
= rate
;
464 else if(!strcmp(s
, "ResetStat"))
466 for(vc
=0; vc
< max_vci
; vc
++)
473 else if(!strcmp(s
, "CLR"))
477 if(vc
< 0 || vc
>= max_vci
)
478 syntax1s1d("%s: invalid VCI used: %d", name
, vc
);
480 if(cpar
[vc
]->received
> 0)
481 clr
= cpar
[vc
]->lost
/ (double)cpar
[vc
]->received
;
491 else if(!strcmp(s
, "CLR0"))
495 if(vc
< 0 || vc
>= max_vci
)
496 syntax1s1d("%s: invalid VCI used: %d", name
, vc
);
498 if(cpar
[vc
]->received0
> 0)
499 clr
= cpar
[vc
]->lost0
/ (double)cpar
[vc
]->received0
;
509 else if(!strcmp(s
, "CLR1"))
513 if(vc
< 0 || vc
>= max_vci
)
514 syntax1s1d("%s: invalid VCI used: %d", name
, vc
);
516 if(cpar
[vc
]->received
- cpar
[vc
]->received0
> 0)
517 clr
= (cpar
[vc
]->lost
- cpar
[vc
]->lost0
) /
518 (double)(cpar
[vc
]->received
- cpar
[vc
]->received0
);
534 ///////////////////////////////////////////////////////////////////////////////
536 ///////////////////////////////////////////////////////////////////////////////
537 void muxCLP::connect(void)
542 baseclass::connect();
544 // check, if there are SCRs given
545 for(i
=1;i
< max_vci
; i
++)
551 // sum up all SCRs given
553 for(i
=1;i
< max_vci
; i
++)
555 double rate
= cpar
[i
]->SCR
;
557 errm1s1d("%s: SCR for connection %d not given",name
,i
);
558 reserved_SCR
+= rate
;
561 for(i
=1;i
< max_vci
; i
++)
562 cpar
[i
]->SCR_ratio
= cpar
[i
]->SCR
/ reserved_SCR
;
565 else // nothing given
568 for(i
=1;i
< max_vci
; i
++)
570 cpar
[i
]->SCR_ratio
= 1.0/max_vci
;
571 cpar
[i
]->SCR
= 1.0/max_vci
;
576 } // muxCLP::connect()