removed apps
[luayats.git] / src / user / clpmux.c
blobb0e8a50be90fcfd80b4eddee380c74f1d6d77142
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // Multiplexer with EPD/PPD and CLP thresholds
4 //
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
19 // OUT=<suc>;
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
26 //
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 ///////////////////////////////////////////////////////////////////////////////
40 #include "clpmux.h"
42 CONSTRUCTOR(MuxCLP, muxCLP);
43 USERCLASS("MuxCLP", MuxCLP);
45 // read additional (compared to mux) parameters
46 void muxCLP::addpars(void)
48 int i;
50 baseclass::addpars();
52 epdThresh = read_int("EPDTHRESH");
53 if (epdThresh <= 0)
54 syntax0("invalid EPDTHRESH");
55 skip(',');
57 clp1Thresh = read_int("CLP1THRESH");
58 if (clp1Thresh <= 0)
59 syntax0("invalid CLP1THRESH");
60 skip(',');
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");
68 skip(',');
70 else
71 epdClp1 = 0;
73 // perfrom DFBA?
74 if(test_word("DFBA"))
76 performDFBA = read_int("DFBA");
77 if (performDFBA < 0 || performDFBA >1)
78 syntax0("DFBA must be 0 or 1");
79 skip(',');
81 else
82 performDFBA = 0;
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");
93 skip(',');
95 else
96 fairClp0 = 0;
98 // boolean, discard CLP0 if above trheshold
99 if(test_word("FBA0"))
101 fba0 = read_int("FBA0");
102 if (fba0 < 0 || fba0 >1)
103 syntax0("FBA0 must be 0 or 1");
104 skip(',');
106 else
107 fba0 = 0;
109 if(fba0 && fairClp0)
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");
121 skip(',');
123 else
124 perform_RED1 = 0;
126 if(perform_RED1)
129 red1.th_l = read_int("RED1_TH_LOW"); // lower threshold for performing RED
130 if(red1.th_l < 0)
131 syntax0("RED1_TH_LOW must be >= 0");
132 else if(red1.th_l >= q.getmax())
133 syntax0("RED1_TH_LOW must be < BUFF");
134 skip(',');
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");
141 skip(',');
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]");
146 skip(',');
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]");
151 skip(',');
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]");
158 skip(',');
160 else
161 red1.useaverage = 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]");
168 skip(',');
170 } // perform RED
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");
179 skip(',');
181 else
182 deliverPt1 = 0;
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();
193 } // init()
196 ///////////////////////////////////////////////////////////////////////////////
197 // late(event *)
198 // a cell has arrived
199 ///////////////////////////////////////////////////////////////////////////////
200 void muxCLP::late(event*)
202 int n;
203 inpstruct *p;
205 // process all arrivals in random order
206 n = inp_ptr - inp_buff;
207 while (n != 0)
209 if (n > 1)
210 p = inp_buff + (my_rand() % n);
211 else
212 p = inp_buff;
214 if (typequery(p->pdata, AAL5CellType))
216 int vc;
217 aal5Cell *pc;
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++;
226 if(pc->clp == 0)
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)
248 int drop;
249 drop = red1.Update(q.q_len);
250 if(drop)
251 cpar[vc]->vciOK = FALSE;
254 // discard clp0-frames if this vc uses more than its fair
255 // share
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)))
286 double p;
287 double X = q.getlen();
288 double Xi = cpar[vc]->qlen;
289 double Z = 1.0; //1.0 - (1.0/max_vci);
290 double a = 0.5;
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
300 if(uniform() <= p)
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)
315 cpar[vc]->vciOK = 0;
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
324 cpar[vc]->lost++;
325 if(pc->clp == 0)
327 cpar[vc]->lost0++;
329 dropItem(p);
330 cpar[vc]->vciOK = FALSE; // drop the rest of the burst
332 else // succesful served
334 cpar[vc]->served++;
335 cpar[vc]->qlen++;
336 if(pc->clp == 0)
337 cpar[vc]->qlen0++;
341 else
343 cpar[vc]->lost++;
344 if(pc->clp == 0)
346 cpar[vc]->lost0++;
348 dropItem(p);
352 else
354 if (q.enqueue(p->pdata) == FALSE)
355 dropItem(p);
358 *p = inp_buff[--n];
360 inp_ptr = inp_buff;
362 if (q.getlen() != 0)
363 alarme( &std_evt, 1);
365 } // late()
368 ///////////////////////////////////////////////////////////////////////////////
369 // early(event *)
370 // serve one data item
371 ///////////////////////////////////////////////////////////////////////////////
372 void muxCLP::early(event *)
374 cell *pc;
375 pc = (cell*) q.dequeue();
376 int vc = pc->vci;
378 cpar[vc]->qlen--;
379 if(pc->clp==0)
380 cpar[vc]->qlen0--;
382 suc->rec(pc, shand);
386 ///////////////////////////////////////////////////////////////////////////////
387 // ResetStatVC(vc)
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;
395 cpar[vc]->lost = 0;
396 cpar[vc]->received0 = 0;
397 cpar[vc]->lost0 = 0;
398 cpar[vc]->served = 0;
400 } // ResetVC(vc)
403 ///////////////////////////////////////////////////////////////////////////////
404 // command()
405 ///////////////////////////////////////////////////////////////////////////////
406 int muxCLP::command(char *s,tok_typ *pv)
408 int vc;
409 double clr;
411 if (baseclass::command(s, pv))
412 return TRUE;
414 if(!strcmp(s, "SetCLP1threshEPD")) // VCI-specific CLP-1-EPD threshold
416 skip('(');
417 vc = read_int(NULL);
418 if(vc < 0 || vc >= max_vci)
419 syntax1s1d("%s: invalid VCI used: %d", name, vc);
421 skip(',');
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);
426 skip(')');
427 return TRUE;
430 else if(!strcmp(s, "SetCLP0threshEPD")) // VCI-specific CLP-1-EPD threshold
432 skip('(');
433 vc = read_int(NULL);
434 if(vc < 0 || vc >= max_vci)
435 syntax1s1d("%s: invalid VCI used: %d", name, vc);
437 skip(',');
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);
442 skip(')');
443 return TRUE;
446 else if(!strcmp(s, "SetSCR"))
448 skip('(');
449 vc = read_int(NULL);
450 if(vc < 0 || vc >= max_vci)
451 syntax1s1d("%s: invalid VCI used: %d", name, vc);
452 skip(',');
453 double rate = read_double(NULL);
454 if(rate <= 0)
455 syntax1s("%s: SCR must be > 0", name);
457 cpar[vc]->SCR = rate;
459 skip(')');
461 pv->tok = NILVAR;
462 return TRUE;
464 else if(!strcmp(s, "ResetStat"))
466 for(vc=0; vc < max_vci; vc++)
467 ResetStatVC(vc);
469 pv->tok = NILVAR;
470 return TRUE;
473 else if(!strcmp(s, "CLR"))
475 skip('(');
476 vc = read_int(NULL);
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;
482 else
483 clr = 0.0;
485 skip(')');
487 pv->val.d = clr;
488 pv->tok = DVAL;
489 return TRUE;
491 else if(!strcmp(s, "CLR0"))
493 skip('(');
494 vc = read_int(NULL);
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;
500 else
501 clr = 0.0;
503 skip(')');
505 pv->val.d = clr;
506 pv->tok = DVAL;
507 return TRUE;
509 else if(!strcmp(s, "CLR1"))
511 skip('(');
512 vc = read_int(NULL);
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);
519 else
520 clr = 0.0;
522 skip(')');
524 pv->val.d = clr;
525 pv->tok = DVAL;
526 return TRUE;
530 return FALSE;
532 } // muxCLP::command
534 ///////////////////////////////////////////////////////////////////////////////
535 // connect
536 ///////////////////////////////////////////////////////////////////////////////
537 void muxCLP::connect(void)
539 int i;
540 int SCR_given = 0;
542 baseclass::connect();
544 // check, if there are SCRs given
545 for(i=1;i < max_vci; i++)
546 if(cpar[i]->SCR > 0)
547 SCR_given = 1;
549 if(SCR_given)
551 // sum up all SCRs given
552 reserved_SCR = 0.0;
553 for(i=1;i < max_vci; i++)
555 double rate = cpar[i]->SCR;
556 if(rate <= 0)
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
567 reserved_SCR = 1.0;
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()