1 /* 2 * PIE - Proportional Integral controller Enhanced AQM algorithm. 3 * 4 * $FreeBSD$ 5 * 6 * Copyright (C) 2016 Centre for Advanced Internet Architectures, 7 * Swinburne University of Technology, Melbourne, Australia. 8 * Portions of this code were made possible in part by a gift from 9 * The Comcast Innovation Fund. 10 * Implemented by Rasool Al-Saadi <ralsaadi@swin.edu.au> 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 #include "opt_inet6.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/kernel.h> 42 #include <sys/lock.h> 43 #include <sys/module.h> 44 #include <sys/mutex.h> 45 #include <sys/priv.h> 46 #include <sys/proc.h> 47 #include <sys/rwlock.h> 48 #include <sys/socket.h> 49 #include <sys/time.h> 50 #include <sys/sysctl.h> 51 52 #include <net/if.h> /* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */ 53 #include <net/netisr.h> 54 #include <net/vnet.h> 55 56 #include <netinet/in.h> 57 #include <netinet/ip.h> /* ip_len, ip_off */ 58 #include <netinet/ip_var.h> /* ip_output(), IP_FORWARDING */ 59 #include <netinet/ip_fw.h> 60 #include <netinet/ip_dummynet.h> 61 #include <netinet/if_ether.h> /* various ether_* routines */ 62 #include <netinet/ip6.h> /* for ip6_input, ip6_output prototypes */ 63 #include <netinet6/ip6_var.h> 64 #include <netpfil/ipfw/dn_heap.h> 65 66 #ifdef NEW_AQM 67 #include <netpfil/ipfw/ip_fw_private.h> 68 #include <netpfil/ipfw/ip_dn_private.h> 69 #include <netpfil/ipfw/dn_aqm.h> 70 #include <netpfil/ipfw/dn_aqm_pie.h> 71 #include <netpfil/ipfw/dn_sched.h> 72 73 /* for debugging */ 74 #include <sys/syslog.h> 75 76 static struct dn_aqm pie_desc; 77 78 /* PIE defaults 79 * target=15ms, tupdate=15ms, max_burst=150ms, 80 * max_ecnth=0.1, alpha=0.125, beta=1.25, 81 */ 82 struct dn_aqm_pie_parms pie_sysctl = 83 { 15 * AQM_TIME_1MS, 15 * AQM_TIME_1MS, 150 * AQM_TIME_1MS, 84 PIE_SCALE/10 , PIE_SCALE * 0.125, PIE_SCALE * 1.25 , 85 PIE_CAPDROP_ENABLED | PIE_DEPRATEEST_ENABLED | PIE_DERAND_ENABLED }; 86 87 static int 88 pie_sysctl_alpha_beta_handler(SYSCTL_HANDLER_ARGS) 89 { 90 int error; 91 long value; 92 93 if (!strcmp(oidp->oid_name,"alpha")) 94 value = pie_sysctl.alpha; 95 else 96 value = pie_sysctl.beta; 97 98 value = value * 1000 / PIE_SCALE; 99 error = sysctl_handle_long(oidp, &value, 0, req); 100 if (error != 0 || req->newptr == NULL) 101 return (error); 102 if (value < 1 || value > 7 * PIE_SCALE) 103 return (EINVAL); 104 value = (value * PIE_SCALE) / 1000; 105 if (!strcmp(oidp->oid_name,"alpha")) 106 pie_sysctl.alpha = value; 107 else 108 pie_sysctl.beta = value; 109 return (0); 110 } 111 112 static int 113 pie_sysctl_target_tupdate_maxb_handler(SYSCTL_HANDLER_ARGS) 114 { 115 int error; 116 long value; 117 118 if (!strcmp(oidp->oid_name,"target")) 119 value = pie_sysctl.qdelay_ref; 120 else if (!strcmp(oidp->oid_name,"tupdate")) 121 value = pie_sysctl.tupdate; 122 else 123 value = pie_sysctl.max_burst; 124 125 value = value / AQM_TIME_1US; 126 error = sysctl_handle_long(oidp, &value, 0, req); 127 if (error != 0 || req->newptr == NULL) 128 return (error); 129 if (value < 1 || value > 10 * AQM_TIME_1S) 130 return (EINVAL); 131 value = value * AQM_TIME_1US; 132 133 if (!strcmp(oidp->oid_name,"target")) 134 pie_sysctl.qdelay_ref = value; 135 else if (!strcmp(oidp->oid_name,"tupdate")) 136 pie_sysctl.tupdate = value; 137 else 138 pie_sysctl.max_burst = value; 139 return (0); 140 } 141 142 static int 143 pie_sysctl_max_ecnth_handler(SYSCTL_HANDLER_ARGS) 144 { 145 int error; 146 long value; 147 148 value = pie_sysctl.max_ecnth; 149 value = value * 1000 / PIE_SCALE; 150 error = sysctl_handle_long(oidp, &value, 0, req); 151 if (error != 0 || req->newptr == NULL) 152 return (error); 153 if (value < 1 || value > PIE_SCALE) 154 return (EINVAL); 155 value = (value * PIE_SCALE) / 1000; 156 pie_sysctl.max_ecnth = value; 157 return (0); 158 } 159 160 /* define PIE sysctl variables */ 161 SYSBEGIN(f4) 162 SYSCTL_DECL(_net_inet); 163 SYSCTL_DECL(_net_inet_ip); 164 SYSCTL_DECL(_net_inet_ip_dummynet); 165 static SYSCTL_NODE(_net_inet_ip_dummynet, OID_AUTO, 166 pie, CTLFLAG_RW, 0, "PIE"); 167 168 #ifdef SYSCTL_NODE 169 SYSCTL_PROC(_net_inet_ip_dummynet_pie, OID_AUTO, target, 170 CTLTYPE_LONG | CTLFLAG_RW, NULL, 0, 171 pie_sysctl_target_tupdate_maxb_handler, "L", 172 "queue target in microsecond"); 173 SYSCTL_PROC(_net_inet_ip_dummynet_pie, OID_AUTO, tupdate, 174 CTLTYPE_LONG | CTLFLAG_RW, NULL, 0, 175 pie_sysctl_target_tupdate_maxb_handler, "L", 176 "the frequency of drop probability calculation in microsecond"); 177 SYSCTL_PROC(_net_inet_ip_dummynet_pie, OID_AUTO, max_burst, 178 CTLTYPE_LONG | CTLFLAG_RW, NULL, 0, 179 pie_sysctl_target_tupdate_maxb_handler, "L", 180 "Burst allowance interval in microsecond"); 181 182 SYSCTL_PROC(_net_inet_ip_dummynet_pie, OID_AUTO, max_ecnth, 183 CTLTYPE_LONG | CTLFLAG_RW, NULL, 0, 184 pie_sysctl_max_ecnth_handler, "L", 185 "ECN safeguard threshold scaled by 1000"); 186 187 SYSCTL_PROC(_net_inet_ip_dummynet_pie, OID_AUTO, alpha, 188 CTLTYPE_LONG | CTLFLAG_RW, NULL, 0, 189 pie_sysctl_alpha_beta_handler, "L", 190 "PIE alpha scaled by 1000"); 191 SYSCTL_PROC(_net_inet_ip_dummynet_pie, OID_AUTO, beta, 192 CTLTYPE_LONG | CTLFLAG_RW, NULL, 0, 193 pie_sysctl_alpha_beta_handler, "L", 194 "beta scaled by 1000"); 195 #endif 196 197 198 /* 199 * Callout function for drop probability calculation 200 * This function is called over tupdate ms and takes pointer of PIE 201 * status variables as an argument 202 */ 203 static void 204 calculate_drop_prob(void *x) 205 { 206 int64_t p, prob, oldprob; 207 struct dn_aqm_pie_parms *pprms; 208 struct pie_status *pst = (struct pie_status *) x; 209 210 pprms = pst->parms; 211 prob = pst->drop_prob; 212 213 /* calculate current qdelay */ 214 if (pprms->flags & PIE_DEPRATEEST_ENABLED) { 215 pst->current_qdelay = ((uint64_t)pst->pq->ni.len_bytes * 216 pst->avg_dq_time) >> PIE_DQ_THRESHOLD_BITS; 217 } 218 219 /* calculate drop probability */ 220 p = (int64_t)pprms->alpha * 221 ((int64_t)pst->current_qdelay - (int64_t)pprms->qdelay_ref); 222 p +=(int64_t) pprms->beta * 223 ((int64_t)pst->current_qdelay - (int64_t)pst->qdelay_old); 224 225 /* We PIE_MAX_PROB shift by 12-bits to increase the division precision */ 226 p *= (PIE_MAX_PROB << 12) / AQM_TIME_1S; 227 228 /* auto-tune drop probability */ 229 if (prob < (PIE_MAX_PROB / 1000000)) /* 0.000001 */ 230 p >>= 11 + PIE_FIX_POINT_BITS + 12; 231 else if (prob < (PIE_MAX_PROB / 100000)) /* 0.00001 */ 232 p >>= 9 + PIE_FIX_POINT_BITS + 12; 233 else if (prob < (PIE_MAX_PROB / 10000)) /* 0.0001 */ 234 p >>= 7 + PIE_FIX_POINT_BITS + 12; 235 else if (prob < (PIE_MAX_PROB / 1000)) /* 0.001 */ 236 p >>= 5 + PIE_FIX_POINT_BITS + 12; 237 else if (prob < (PIE_MAX_PROB / 100)) /* 0.01 */ 238 p >>= 3 + PIE_FIX_POINT_BITS + 12; 239 else if (prob < (PIE_MAX_PROB / 10)) /* 0.1 */ 240 p >>= 1 + PIE_FIX_POINT_BITS + 12; 241 else 242 p >>= PIE_FIX_POINT_BITS + 12; 243 244 oldprob = prob; 245 246 /* Cap Drop adjustment */ 247 if ((pprms->flags & PIE_CAPDROP_ENABLED) && prob >= PIE_MAX_PROB / 10 248 && p > PIE_MAX_PROB / 50 ) 249 p = PIE_MAX_PROB / 50; 250 251 prob = prob + p; 252 253 /* decay the drop probability exponentially */ 254 if (pst->current_qdelay == 0 && pst->qdelay_old == 0) 255 /* 0.98 ~= 1- 1/64 */ 256 prob = prob - (prob >> 6); 257 258 259 /* check for multiplication overflow/underflow */ 260 if (p>0) { 261 if (prob<oldprob) { 262 D("overflow"); 263 prob= PIE_MAX_PROB; 264 } 265 } 266 else 267 if (prob>oldprob) { 268 prob= 0; 269 D("underflow"); 270 } 271 272 /* make drop probability between 0 and PIE_MAX_PROB*/ 273 if (prob < 0) 274 prob = 0; 275 else if (prob > PIE_MAX_PROB) 276 prob = PIE_MAX_PROB; 277 278 pst->drop_prob = prob; 279 280 /* store current queue delay value in old queue delay*/ 281 pst->qdelay_old = pst->current_qdelay; 282 283 /* update burst allowance */ 284 if ((pst->sflags & PIE_ACTIVE) && pst->burst_allowance>0) { 285 286 if (pst->burst_allowance > pprms->tupdate ) 287 pst->burst_allowance -= pprms->tupdate; 288 else 289 pst->burst_allowance = 0; 290 } 291 292 /* reschedule calculate_drop_prob function */ 293 if (pst->sflags & PIE_ACTIVE) 294 callout_reset_sbt(&pst->aqm_pie_callout, 295 (uint64_t)pprms->tupdate * SBT_1US, 0, calculate_drop_prob, pst, 0); 296 297 mtx_unlock(&pst->lock_mtx); 298 } 299 300 /* 301 * Extract a packet from the head of queue 'q' 302 * Return a packet or NULL if the queue is empty. 303 * If getts is set, also extract packet's timestamp from mtag. 304 */ 305 static struct mbuf * 306 pie_extract_head(struct dn_queue *q, aqm_time_t *pkt_ts, int getts) 307 { 308 struct m_tag *mtag; 309 struct mbuf *m = q->mq.head; 310 311 if (m == NULL) 312 return m; 313 q->mq.head = m->m_nextpkt; 314 315 /* Update stats */ 316 update_stats(q, -m->m_pkthdr.len, 0); 317 318 if (q->ni.length == 0) /* queue is now idle */ 319 q->q_time = dn_cfg.curr_time; 320 321 if (getts) { 322 /* extract packet TS*/ 323 mtag = m_tag_locate(m, MTAG_ABI_COMPAT, DN_AQM_MTAG_TS, NULL); 324 if (mtag == NULL) { 325 D("PIE timestamp mtag not found!"); 326 *pkt_ts = 0; 327 } else { 328 *pkt_ts = *(aqm_time_t *)(mtag + 1); 329 m_tag_delete(m,mtag); 330 } 331 } 332 return m; 333 } 334 335 /* 336 * Initiate PIE variable and optionally activate it 337 */ 338 __inline static void 339 init_activate_pie(struct pie_status *pst, int resettimer) 340 { 341 struct dn_aqm_pie_parms *pprms; 342 343 mtx_lock(&pst->lock_mtx); 344 pprms = pst->parms; 345 pst->drop_prob = 0; 346 pst->qdelay_old = 0; 347 pst->burst_allowance = pprms->max_burst; 348 pst->accu_prob = 0; 349 pst->dq_count = 0; 350 pst->avg_dq_time = 0; 351 pst->sflags = PIE_INMEASUREMENT; 352 pst->measurement_start = AQM_UNOW; 353 354 if (resettimer) { 355 pst->sflags |= PIE_ACTIVE; 356 callout_reset_sbt(&pst->aqm_pie_callout, 357 (uint64_t)pprms->tupdate * SBT_1US, 358 0, calculate_drop_prob, pst, 0); 359 } 360 //DX(2, "PIE Activated"); 361 mtx_unlock(&pst->lock_mtx); 362 } 363 364 /* 365 * Deactivate PIE and stop probe update callout 366 */ 367 __inline static void 368 deactivate_pie(struct pie_status *pst) 369 { 370 mtx_lock(&pst->lock_mtx); 371 pst->sflags &= ~(PIE_ACTIVE | PIE_INMEASUREMENT); 372 callout_stop(&pst->aqm_pie_callout); 373 //D("PIE Deactivated"); 374 mtx_unlock(&pst->lock_mtx); 375 } 376 377 /* 378 * Dequeue and return a pcaket from queue 'q' or NULL if 'q' is empty. 379 * Also, caculate depature time or queue delay using timestamp 380 */ 381 static struct mbuf * 382 aqm_pie_dequeue(struct dn_queue *q) 383 { 384 struct mbuf *m; 385 struct dn_flow *ni; /* stats for scheduler instance */ 386 struct dn_aqm_pie_parms *pprms; 387 struct pie_status *pst; 388 aqm_time_t now; 389 aqm_time_t pkt_ts, dq_time; 390 int32_t w; 391 392 pst = q->aqm_status; 393 pprms = pst->parms; 394 ni = &q->_si->ni; 395 396 /*we extarct packet ts only when Departure Rate Estimation dis not used*/ 397 m = pie_extract_head(q, &pkt_ts, !(pprms->flags & PIE_DEPRATEEST_ENABLED)); 398 399 if (!m || !(pst->sflags & PIE_ACTIVE)) 400 return m; 401 402 now = AQM_UNOW; 403 if (pprms->flags & PIE_DEPRATEEST_ENABLED) { 404 /* calculate average depature time */ 405 if(pst->sflags & PIE_INMEASUREMENT) { 406 pst->dq_count += m->m_pkthdr.len; 407 408 if (pst->dq_count >= PIE_DQ_THRESHOLD) { 409 dq_time = now - pst->measurement_start; 410 411 /* 412 * if we don't have old avg dq_time i.e PIE is (re)initialized, 413 * don't use weight to calculate new avg_dq_time 414 */ 415 if(pst->avg_dq_time == 0) 416 pst->avg_dq_time = dq_time; 417 else { 418 /* 419 * weight = PIE_DQ_THRESHOLD/2^6, but we scaled 420 * weight by 2^8. Thus, scaled 421 * weight = PIE_DQ_THRESHOLD /2^8 422 * */ 423 w = PIE_DQ_THRESHOLD >> 8; 424 pst->avg_dq_time = (dq_time* w 425 + (pst->avg_dq_time * ((1L << 8) - w))) >> 8; 426 pst->sflags &= ~PIE_INMEASUREMENT; 427 } 428 } 429 } 430 431 /* 432 * Start new measurment cycle when the queue has 433 * PIE_DQ_THRESHOLD worth of bytes. 434 */ 435 if(!(pst->sflags & PIE_INMEASUREMENT) && 436 q->ni.len_bytes >= PIE_DQ_THRESHOLD) { 437 pst->sflags |= PIE_INMEASUREMENT; 438 pst->measurement_start = now; 439 pst->dq_count = 0; 440 } 441 } 442 /* Optionally, use packet timestamp to estimate queue delay */ 443 else 444 pst->current_qdelay = now - pkt_ts; 445 446 return m; 447 } 448 449 /* 450 * Enqueue a packet in q, subject to space and PIE queue management policy 451 * (whose parameters are in q->fs). 452 * Update stats for the queue and the scheduler. 453 * Return 0 on success, 1 on drop. The packet is consumed anyways. 454 */ 455 static int 456 aqm_pie_enqueue(struct dn_queue *q, struct mbuf* m) 457 { 458 struct dn_fs *f; 459 uint64_t len; 460 uint32_t qlen; 461 struct pie_status *pst; 462 struct dn_aqm_pie_parms *pprms; 463 int t; 464 465 len = m->m_pkthdr.len; 466 pst = q->aqm_status; 467 if(!pst) { 468 DX(2, "PIE queue is not initialized\n"); 469 update_stats(q, 0, 1); 470 FREE_PKT(m); 471 return 1; 472 } 473 474 f = &(q->fs->fs); 475 pprms = pst->parms; 476 t = ENQUE; 477 478 /* get current queue length in bytes or packets*/ 479 qlen = (f->flags & DN_QSIZE_BYTES) ? 480 q->ni.len_bytes : q->ni.length; 481 482 /* check for queue size and drop the tail if exceed queue limit*/ 483 if (qlen >= f->qsize) 484 t = DROP; 485 /* drop/mark the packet when PIE is active and burst time elapsed */ 486 else if ((pst->sflags & PIE_ACTIVE) && pst->burst_allowance==0 487 && drop_early(pst, q->ni.len_bytes) == DROP) { 488 /* 489 * if drop_prob over ECN threshold, drop the packet 490 * otherwise mark and enqueue it. 491 */ 492 if ((pprms->flags & PIE_ECN_ENABLED) && pst->drop_prob < 493 (pprms->max_ecnth << (PIE_PROB_BITS - PIE_FIX_POINT_BITS)) 494 && ecn_mark(m)) 495 t = ENQUE; 496 else 497 t = DROP; 498 } 499 500 /* Turn PIE on when 1/3 of the queue is full */ 501 if (!(pst->sflags & PIE_ACTIVE) && qlen >= pst->one_third_q_size) { 502 init_activate_pie(pst, 1); 503 } 504 505 /* Reset burst tolerance and optinally turn PIE off*/ 506 if ((pst->sflags & PIE_ACTIVE) && pst->drop_prob == 0 && 507 pst->current_qdelay < (pprms->qdelay_ref >> 1) && 508 pst->qdelay_old < (pprms->qdelay_ref >> 1)) { 509 510 pst->burst_allowance = pprms->max_burst; 511 if ((pprms->flags & PIE_ON_OFF_MODE_ENABLED) && qlen<=0) 512 deactivate_pie(pst); 513 } 514 515 /* Timestamp the packet if Departure Rate Estimation is disabled */ 516 if (t != DROP && !(pprms->flags & PIE_DEPRATEEST_ENABLED)) { 517 /* Add TS to mbuf as a TAG */ 518 struct m_tag *mtag; 519 mtag = m_tag_locate(m, MTAG_ABI_COMPAT, DN_AQM_MTAG_TS, NULL); 520 if (mtag == NULL) 521 mtag = m_tag_alloc(MTAG_ABI_COMPAT, DN_AQM_MTAG_TS, 522 sizeof(aqm_time_t), M_NOWAIT); 523 if (mtag == NULL) { 524 m_freem(m); 525 t = DROP; 526 } 527 *(aqm_time_t *)(mtag + 1) = AQM_UNOW; 528 m_tag_prepend(m, mtag); 529 } 530 531 if (t != DROP) { 532 mq_append(&q->mq, m); 533 update_stats(q, len, 0); 534 return (0); 535 } else { 536 update_stats(q, 0, 1); 537 538 /* reset accu_prob after packet drop */ 539 pst->accu_prob = 0; 540 FREE_PKT(m); 541 return 1; 542 } 543 return 0; 544 } 545 546 /* 547 * initialize PIE for queue 'q' 548 * First allocate memory for PIE status. 549 */ 550 static int 551 aqm_pie_init(struct dn_queue *q) 552 { 553 struct pie_status *pst; 554 struct dn_aqm_pie_parms *pprms; 555 int err = 0; 556 557 pprms = q->fs->aqmcfg; 558 559 do { /* exit with break when error occurs*/ 560 if (!pprms){ 561 DX(2, "AQM_PIE is not configured"); 562 err = EINVAL; 563 break; 564 } 565 566 q->aqm_status = malloc(sizeof(struct pie_status), 567 M_DUMMYNET, M_NOWAIT | M_ZERO); 568 if (q->aqm_status == NULL) { 569 D("cannot allocate PIE private data"); 570 err = ENOMEM ; 571 break; 572 } 573 574 pst = q->aqm_status; 575 /* increase reference count for PIE module */ 576 pie_desc.ref_count++; 577 578 pst->pq = q; 579 pst->parms = pprms; 580 581 /* For speed optimization, we caculate 1/3 queue size once here */ 582 // we can use x/3 = (x >>2) + (x >>4) + (x >>7) 583 pst->one_third_q_size = q->fs->fs.qsize/3; 584 585 mtx_init(&pst->lock_mtx, "mtx_pie", NULL, MTX_DEF); 586 callout_init_mtx(&pst->aqm_pie_callout, &pst->lock_mtx, 587 CALLOUT_RETURNUNLOCKED); 588 589 pst->current_qdelay = 0; 590 init_activate_pie(pst, !(pprms->flags & PIE_ON_OFF_MODE_ENABLED)); 591 592 //DX(2, "aqm_PIE_init"); 593 594 } while(0); 595 596 return err; 597 } 598 599 /* 600 * Callout function to destroy pie mtx and free PIE status memory 601 */ 602 static void 603 pie_callout_cleanup(void *x) 604 { 605 struct pie_status *pst = (struct pie_status *) x; 606 607 mtx_unlock(&pst->lock_mtx); 608 mtx_destroy(&pst->lock_mtx); 609 free(x, M_DUMMYNET); 610 DN_BH_WLOCK(); 611 pie_desc.ref_count--; 612 DN_BH_WUNLOCK(); 613 } 614 615 /* 616 * Clean up PIE status for queue 'q' 617 * Destroy memory allocated for PIE status. 618 */ 619 static int 620 aqm_pie_cleanup(struct dn_queue *q) 621 { 622 623 if(!q) { 624 D("q is null"); 625 return 0; 626 } 627 struct pie_status *pst = q->aqm_status; 628 if(!pst) { 629 //D("queue is already cleaned up"); 630 return 0; 631 } 632 if(!q->fs || !q->fs->aqmcfg) { 633 D("fs is null or no cfg"); 634 return 1; 635 } 636 if (q->fs->aqmfp && q->fs->aqmfp->type !=DN_AQM_PIE) { 637 D("Not PIE fs (%d)", q->fs->fs.fs_nr); 638 return 1; 639 } 640 641 /* 642 * Free PIE status allocated memory using pie_callout_cleanup() callout 643 * function to avoid any potential race. 644 * We reset aqm_pie_callout to call pie_callout_cleanup() in next 1um. This 645 * stops the scheduled calculate_drop_prob() callout and call pie_callout_cleanup() 646 * which does memory freeing. 647 */ 648 mtx_lock(&pst->lock_mtx); 649 callout_reset_sbt(&pst->aqm_pie_callout, 650 SBT_1US, 0, pie_callout_cleanup, pst, 0); 651 q->aqm_status = NULL; 652 mtx_unlock(&pst->lock_mtx); 653 654 return 0; 655 } 656 657 /* 658 * Config PIE parameters 659 * also allocate memory for PIE configurations 660 */ 661 static int 662 aqm_pie_config(struct dn_fsk* fs, struct dn_extra_parms *ep, int len) 663 { 664 struct dn_aqm_pie_parms *pcfg; 665 666 int l = sizeof(struct dn_extra_parms); 667 if (len < l) { 668 D("invalid sched parms length got %d need %d", len, l); 669 return EINVAL; 670 } 671 /* we free the old cfg because maybe the orignal allocation 672 * was used for diffirent AQM type. 673 */ 674 if (fs->aqmcfg) { 675 free(fs->aqmcfg, M_DUMMYNET); 676 fs->aqmcfg = NULL; 677 } 678 679 fs->aqmcfg = malloc(sizeof(struct dn_aqm_pie_parms), 680 M_DUMMYNET, M_NOWAIT | M_ZERO); 681 if (fs->aqmcfg== NULL) { 682 D("cannot allocate PIE configuration parameters"); 683 return ENOMEM; 684 } 685 686 /* par array contains pie configuration as follow 687 * 0- qdelay_ref,1- tupdate, 2- max_burst 688 * 3- max_ecnth, 4- alpha, 5- beta, 6- flags 689 */ 690 691 /* configure PIE parameters */ 692 pcfg = fs->aqmcfg; 693 694 if (ep->par[0] < 0) 695 pcfg->qdelay_ref = pie_sysctl.qdelay_ref * AQM_TIME_1US; 696 else 697 pcfg->qdelay_ref = ep->par[0]; 698 if (ep->par[1] < 0) 699 pcfg->tupdate = pie_sysctl.tupdate * AQM_TIME_1US; 700 else 701 pcfg->tupdate = ep->par[1]; 702 if (ep->par[2] < 0) 703 pcfg->max_burst = pie_sysctl.max_burst * AQM_TIME_1US; 704 else 705 pcfg->max_burst = ep->par[2]; 706 if (ep->par[3] < 0) 707 pcfg->max_ecnth = pie_sysctl.max_ecnth; 708 else 709 pcfg->max_ecnth = ep->par[3]; 710 if (ep->par[4] < 0) 711 pcfg->alpha = pie_sysctl.alpha; 712 else 713 pcfg->alpha = ep->par[4]; 714 if (ep->par[5] < 0) 715 pcfg->beta = pie_sysctl.beta; 716 else 717 pcfg->beta = ep->par[5]; 718 if (ep->par[6] < 0) 719 pcfg->flags = pie_sysctl.flags; 720 else 721 pcfg->flags = ep->par[6]; 722 723 /* bound PIE configurations */ 724 pcfg->qdelay_ref = BOUND_VAR(pcfg->qdelay_ref, 1, 10 * AQM_TIME_1S); 725 pcfg->tupdate = BOUND_VAR(pcfg->tupdate, 1, 10 * AQM_TIME_1S); 726 pcfg->max_burst = BOUND_VAR(pcfg->max_burst, 0, 10 * AQM_TIME_1S); 727 pcfg->max_ecnth = BOUND_VAR(pcfg->max_ecnth, 0, PIE_SCALE); 728 pcfg->alpha = BOUND_VAR(pcfg->alpha, 0, 7 * PIE_SCALE); 729 pcfg->beta = BOUND_VAR(pcfg->beta, 0 , 7 * PIE_SCALE); 730 731 pie_desc.cfg_ref_count++; 732 //D("pie cfg_ref_count=%d", pie_desc.cfg_ref_count); 733 return 0; 734 } 735 736 /* 737 * Deconfigure PIE and free memory allocation 738 */ 739 static int 740 aqm_pie_deconfig(struct dn_fsk* fs) 741 { 742 if (fs && fs->aqmcfg) { 743 free(fs->aqmcfg, M_DUMMYNET); 744 fs->aqmcfg = NULL; 745 pie_desc.cfg_ref_count--; 746 } 747 return 0; 748 } 749 750 /* 751 * Retrieve PIE configuration parameters. 752 */ 753 static int 754 aqm_pie_getconfig (struct dn_fsk *fs, struct dn_extra_parms * ep) 755 { 756 struct dn_aqm_pie_parms *pcfg; 757 if (fs->aqmcfg) { 758 strcpy(ep->name, pie_desc.name); 759 pcfg = fs->aqmcfg; 760 ep->par[0] = pcfg->qdelay_ref / AQM_TIME_1US; 761 ep->par[1] = pcfg->tupdate / AQM_TIME_1US; 762 ep->par[2] = pcfg->max_burst / AQM_TIME_1US; 763 ep->par[3] = pcfg->max_ecnth; 764 ep->par[4] = pcfg->alpha; 765 ep->par[5] = pcfg->beta; 766 ep->par[6] = pcfg->flags; 767 768 return 0; 769 } 770 return 1; 771 } 772 773 static struct dn_aqm pie_desc = { 774 _SI( .type = ) DN_AQM_PIE, 775 _SI( .name = ) "PIE", 776 _SI( .ref_count = ) 0, 777 _SI( .cfg_ref_count = ) 0, 778 _SI( .enqueue = ) aqm_pie_enqueue, 779 _SI( .dequeue = ) aqm_pie_dequeue, 780 _SI( .config = ) aqm_pie_config, 781 _SI( .deconfig = ) aqm_pie_deconfig, 782 _SI( .getconfig = ) aqm_pie_getconfig, 783 _SI( .init = ) aqm_pie_init, 784 _SI( .cleanup = ) aqm_pie_cleanup, 785 }; 786 787 DECLARE_DNAQM_MODULE(dn_aqm_pie, &pie_desc); 788 #endif 789