1 /*- 2 * Copyright (C) 1998-2003 3 * Sony Computer Science Laboratories Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 /*- 27 * Copyright (c) 1990-1994 Regents of the University of California. 28 * All rights reserved. 29 * 30 * Redistribution and use in source and binary forms, with or without 31 * modification, are permitted provided that the following conditions 32 * are met: 33 * 1. Redistributions of source code must retain the above copyright 34 * notice, this list of conditions and the following disclaimer. 35 * 2. Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in the 37 * documentation and/or other materials provided with the distribution. 38 * 3. All advertising materials mentioning features or use of this software 39 * must display the following acknowledgement: 40 * This product includes software developed by the Computer Systems 41 * Engineering Group at Lawrence Berkeley Laboratory. 42 * 4. Neither the name of the University nor of the Laboratory may be used 43 * to endorse or promote products derived from this software without 44 * specific prior written permission. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 * SUCH DAMAGE. 57 * 58 * $KAME: altq_rio.c,v 1.17 2003/07/10 12:07:49 kjc Exp $ 59 * $FreeBSD$ 60 */ 61 62 #include "opt_altq.h" 63 #include "opt_inet.h" 64 #include "opt_inet6.h" 65 #ifdef ALTQ_RIO /* rio is enabled by ALTQ_RIO option in opt_altq.h */ 66 67 #include <sys/param.h> 68 #include <sys/malloc.h> 69 #include <sys/mbuf.h> 70 #include <sys/socket.h> 71 #include <sys/systm.h> 72 #include <sys/errno.h> 73 #if 1 /* ALTQ3_COMPAT */ 74 #include <sys/proc.h> 75 #include <sys/sockio.h> 76 #include <sys/kernel.h> 77 #endif 78 79 #include <net/if.h> 80 #include <net/if_var.h> 81 82 #include <netinet/in.h> 83 #include <netinet/in_systm.h> 84 #include <netinet/ip.h> 85 #ifdef INET6 86 #include <netinet/ip6.h> 87 #endif 88 89 #include <netpfil/pf/pf.h> 90 #include <netpfil/pf/pf_altq.h> 91 #include <net/altq/altq.h> 92 #include <net/altq/altq_cdnr.h> 93 #include <net/altq/altq_red.h> 94 #include <net/altq/altq_rio.h> 95 #ifdef ALTQ3_COMPAT 96 #include <net/altq/altq_conf.h> 97 #endif 98 99 /* 100 * RIO: RED with IN/OUT bit 101 * described in 102 * "Explicit Allocation of Best Effort Packet Delivery Service" 103 * David D. Clark and Wenjia Fang, MIT Lab for Computer Science 104 * http://diffserv.lcs.mit.edu/Papers/exp-alloc-ddc-wf.{ps,pdf} 105 * 106 * this implementation is extended to support more than 2 drop precedence 107 * values as described in RFC2597 (Assured Forwarding PHB Group). 108 * 109 */ 110 /* 111 * AF DS (differentiated service) codepoints. 112 * (classes can be mapped to CBQ or H-FSC classes.) 113 * 114 * 0 1 2 3 4 5 6 7 115 * +---+---+---+---+---+---+---+---+ 116 * | CLASS |DropPre| 0 | CU | 117 * +---+---+---+---+---+---+---+---+ 118 * 119 * class 1: 001 120 * class 2: 010 121 * class 3: 011 122 * class 4: 100 123 * 124 * low drop prec: 01 125 * medium drop prec: 10 126 * high drop prec: 01 127 */ 128 129 /* normal red parameters */ 130 #define W_WEIGHT 512 /* inverse of weight of EWMA (511/512) */ 131 /* q_weight = 0.00195 */ 132 133 /* red parameters for a slow link */ 134 #define W_WEIGHT_1 128 /* inverse of weight of EWMA (127/128) */ 135 /* q_weight = 0.0078125 */ 136 137 /* red parameters for a very slow link (e.g., dialup) */ 138 #define W_WEIGHT_2 64 /* inverse of weight of EWMA (63/64) */ 139 /* q_weight = 0.015625 */ 140 141 /* fixed-point uses 12-bit decimal places */ 142 #define FP_SHIFT 12 /* fixed-point shift */ 143 144 /* red parameters for drop probability */ 145 #define INV_P_MAX 10 /* inverse of max drop probability */ 146 #define TH_MIN 5 /* min threshold */ 147 #define TH_MAX 15 /* max threshold */ 148 149 #define RIO_LIMIT 60 /* default max queue length */ 150 #define RIO_STATS /* collect statistics */ 151 152 #define TV_DELTA(a, b, delta) { \ 153 register int xxs; \ 154 \ 155 delta = (a)->tv_usec - (b)->tv_usec; \ 156 if ((xxs = (a)->tv_sec - (b)->tv_sec) != 0) { \ 157 if (xxs < 0) { \ 158 delta = 60000000; \ 159 } else if (xxs > 4) { \ 160 if (xxs > 60) \ 161 delta = 60000000; \ 162 else \ 163 delta += xxs * 1000000; \ 164 } else while (xxs > 0) { \ 165 delta += 1000000; \ 166 xxs--; \ 167 } \ 168 } \ 169 } 170 171 #ifdef ALTQ3_COMPAT 172 /* rio_list keeps all rio_queue_t's allocated. */ 173 static rio_queue_t *rio_list = NULL; 174 #endif 175 /* default rio parameter values */ 176 static struct redparams default_rio_params[RIO_NDROPPREC] = { 177 /* th_min, th_max, inv_pmax */ 178 { TH_MAX * 2 + TH_MIN, TH_MAX * 3, INV_P_MAX }, /* low drop precedence */ 179 { TH_MAX + TH_MIN, TH_MAX * 2, INV_P_MAX }, /* medium drop precedence */ 180 { TH_MIN, TH_MAX, INV_P_MAX } /* high drop precedence */ 181 }; 182 183 /* internal function prototypes */ 184 static int dscp2index(u_int8_t); 185 #ifdef ALTQ3_COMPAT 186 static int rio_enqueue(struct ifaltq *, struct mbuf *, struct altq_pktattr *); 187 static struct mbuf *rio_dequeue(struct ifaltq *, int); 188 static int rio_request(struct ifaltq *, int, void *); 189 static int rio_detach(rio_queue_t *); 190 191 /* 192 * rio device interface 193 */ 194 altqdev_decl(rio); 195 196 #endif /* ALTQ3_COMPAT */ 197 198 rio_t * 199 rio_alloc(int weight, struct redparams *params, int flags, int pkttime) 200 { 201 rio_t *rp; 202 int w, i; 203 int npkts_per_sec; 204 205 rp = malloc(sizeof(rio_t), M_DEVBUF, M_NOWAIT | M_ZERO); 206 if (rp == NULL) 207 return (NULL); 208 209 rp->rio_flags = flags; 210 if (pkttime == 0) 211 /* default packet time: 1000 bytes / 10Mbps * 8 * 1000000 */ 212 rp->rio_pkttime = 800; 213 else 214 rp->rio_pkttime = pkttime; 215 216 if (weight != 0) 217 rp->rio_weight = weight; 218 else { 219 /* use default */ 220 rp->rio_weight = W_WEIGHT; 221 222 /* when the link is very slow, adjust red parameters */ 223 npkts_per_sec = 1000000 / rp->rio_pkttime; 224 if (npkts_per_sec < 50) { 225 /* up to about 400Kbps */ 226 rp->rio_weight = W_WEIGHT_2; 227 } else if (npkts_per_sec < 300) { 228 /* up to about 2.4Mbps */ 229 rp->rio_weight = W_WEIGHT_1; 230 } 231 } 232 233 /* calculate wshift. weight must be power of 2 */ 234 w = rp->rio_weight; 235 for (i = 0; w > 1; i++) 236 w = w >> 1; 237 rp->rio_wshift = i; 238 w = 1 << rp->rio_wshift; 239 if (w != rp->rio_weight) { 240 printf("invalid weight value %d for red! use %d\n", 241 rp->rio_weight, w); 242 rp->rio_weight = w; 243 } 244 245 /* allocate weight table */ 246 rp->rio_wtab = wtab_alloc(rp->rio_weight); 247 248 for (i = 0; i < RIO_NDROPPREC; i++) { 249 struct dropprec_state *prec = &rp->rio_precstate[i]; 250 251 prec->avg = 0; 252 prec->idle = 1; 253 254 if (params == NULL || params[i].inv_pmax == 0) 255 prec->inv_pmax = default_rio_params[i].inv_pmax; 256 else 257 prec->inv_pmax = params[i].inv_pmax; 258 if (params == NULL || params[i].th_min == 0) 259 prec->th_min = default_rio_params[i].th_min; 260 else 261 prec->th_min = params[i].th_min; 262 if (params == NULL || params[i].th_max == 0) 263 prec->th_max = default_rio_params[i].th_max; 264 else 265 prec->th_max = params[i].th_max; 266 267 /* 268 * th_min_s and th_max_s are scaled versions of th_min 269 * and th_max to be compared with avg. 270 */ 271 prec->th_min_s = prec->th_min << (rp->rio_wshift + FP_SHIFT); 272 prec->th_max_s = prec->th_max << (rp->rio_wshift + FP_SHIFT); 273 274 /* 275 * precompute probability denominator 276 * probd = (2 * (TH_MAX-TH_MIN) / pmax) in fixed-point 277 */ 278 prec->probd = (2 * (prec->th_max - prec->th_min) 279 * prec->inv_pmax) << FP_SHIFT; 280 281 microtime(&prec->last); 282 } 283 284 return (rp); 285 } 286 287 void 288 rio_destroy(rio_t *rp) 289 { 290 wtab_destroy(rp->rio_wtab); 291 free(rp, M_DEVBUF); 292 } 293 294 void 295 rio_getstats(rio_t *rp, struct redstats *sp) 296 { 297 int i; 298 299 for (i = 0; i < RIO_NDROPPREC; i++) { 300 bcopy(&rp->q_stats[i], sp, sizeof(struct redstats)); 301 sp->q_avg = rp->rio_precstate[i].avg >> rp->rio_wshift; 302 sp++; 303 } 304 } 305 306 #if (RIO_NDROPPREC == 3) 307 /* 308 * internally, a drop precedence value is converted to an index 309 * starting from 0. 310 */ 311 static int 312 dscp2index(u_int8_t dscp) 313 { 314 int dpindex = dscp & AF_DROPPRECMASK; 315 316 if (dpindex == 0) 317 return (0); 318 return ((dpindex >> 3) - 1); 319 } 320 #endif 321 322 #if 1 323 /* 324 * kludge: when a packet is dequeued, we need to know its drop precedence 325 * in order to keep the queue length of each drop precedence. 326 * use m_pkthdr.rcvif to pass this info. 327 */ 328 #define RIOM_SET_PRECINDEX(m, idx) \ 329 do { (m)->m_pkthdr.rcvif = (void *)((long)(idx)); } while (0) 330 #define RIOM_GET_PRECINDEX(m) \ 331 ({ long idx; idx = (long)((m)->m_pkthdr.rcvif); \ 332 (m)->m_pkthdr.rcvif = NULL; idx; }) 333 #endif 334 335 int 336 rio_addq(rio_t *rp, class_queue_t *q, struct mbuf *m, 337 struct altq_pktattr *pktattr) 338 { 339 int avg, droptype; 340 u_int8_t dsfield, odsfield; 341 int dpindex, i, n, t; 342 struct timeval now; 343 struct dropprec_state *prec; 344 345 dsfield = odsfield = read_dsfield(m, pktattr); 346 dpindex = dscp2index(dsfield); 347 348 /* 349 * update avg of the precedence states whose drop precedence 350 * is larger than or equal to the drop precedence of the packet 351 */ 352 now.tv_sec = 0; 353 for (i = dpindex; i < RIO_NDROPPREC; i++) { 354 prec = &rp->rio_precstate[i]; 355 avg = prec->avg; 356 if (prec->idle) { 357 prec->idle = 0; 358 if (now.tv_sec == 0) 359 microtime(&now); 360 t = (now.tv_sec - prec->last.tv_sec); 361 if (t > 60) 362 avg = 0; 363 else { 364 t = t * 1000000 + 365 (now.tv_usec - prec->last.tv_usec); 366 n = t / rp->rio_pkttime; 367 /* calculate (avg = (1 - Wq)^n * avg) */ 368 if (n > 0) 369 avg = (avg >> FP_SHIFT) * 370 pow_w(rp->rio_wtab, n); 371 } 372 } 373 374 /* run estimator. (avg is scaled by WEIGHT in fixed-point) */ 375 avg += (prec->qlen << FP_SHIFT) - (avg >> rp->rio_wshift); 376 prec->avg = avg; /* save the new value */ 377 /* 378 * count keeps a tally of arriving traffic that has not 379 * been dropped. 380 */ 381 prec->count++; 382 } 383 384 prec = &rp->rio_precstate[dpindex]; 385 avg = prec->avg; 386 387 /* see if we drop early */ 388 droptype = DTYPE_NODROP; 389 if (avg >= prec->th_min_s && prec->qlen > 1) { 390 if (avg >= prec->th_max_s) { 391 /* avg >= th_max: forced drop */ 392 droptype = DTYPE_FORCED; 393 } else if (prec->old == 0) { 394 /* first exceeds th_min */ 395 prec->count = 1; 396 prec->old = 1; 397 } else if (drop_early((avg - prec->th_min_s) >> rp->rio_wshift, 398 prec->probd, prec->count)) { 399 /* unforced drop by red */ 400 droptype = DTYPE_EARLY; 401 } 402 } else { 403 /* avg < th_min */ 404 prec->old = 0; 405 } 406 407 /* 408 * if the queue length hits the hard limit, it's a forced drop. 409 */ 410 if (droptype == DTYPE_NODROP && qlen(q) >= qlimit(q)) 411 droptype = DTYPE_FORCED; 412 413 if (droptype != DTYPE_NODROP) { 414 /* always drop incoming packet (as opposed to randomdrop) */ 415 for (i = dpindex; i < RIO_NDROPPREC; i++) 416 rp->rio_precstate[i].count = 0; 417 #ifdef RIO_STATS 418 if (droptype == DTYPE_EARLY) 419 rp->q_stats[dpindex].drop_unforced++; 420 else 421 rp->q_stats[dpindex].drop_forced++; 422 PKTCNTR_ADD(&rp->q_stats[dpindex].drop_cnt, m_pktlen(m)); 423 #endif 424 m_freem(m); 425 return (-1); 426 } 427 428 for (i = dpindex; i < RIO_NDROPPREC; i++) 429 rp->rio_precstate[i].qlen++; 430 431 /* save drop precedence index in mbuf hdr */ 432 RIOM_SET_PRECINDEX(m, dpindex); 433 434 if (rp->rio_flags & RIOF_CLEARDSCP) 435 dsfield &= ~DSCP_MASK; 436 437 if (dsfield != odsfield) 438 write_dsfield(m, pktattr, dsfield); 439 440 _addq(q, m); 441 442 #ifdef RIO_STATS 443 PKTCNTR_ADD(&rp->q_stats[dpindex].xmit_cnt, m_pktlen(m)); 444 #endif 445 return (0); 446 } 447 448 struct mbuf * 449 rio_getq(rio_t *rp, class_queue_t *q) 450 { 451 struct mbuf *m; 452 int dpindex, i; 453 454 if ((m = _getq(q)) == NULL) 455 return NULL; 456 457 dpindex = RIOM_GET_PRECINDEX(m); 458 for (i = dpindex; i < RIO_NDROPPREC; i++) { 459 if (--rp->rio_precstate[i].qlen == 0) { 460 if (rp->rio_precstate[i].idle == 0) { 461 rp->rio_precstate[i].idle = 1; 462 microtime(&rp->rio_precstate[i].last); 463 } 464 } 465 } 466 return (m); 467 } 468 469 #ifdef ALTQ3_COMPAT 470 int 471 rioopen(dev, flag, fmt, p) 472 dev_t dev; 473 int flag, fmt; 474 #if (__FreeBSD_version > 500000) 475 struct thread *p; 476 #else 477 struct proc *p; 478 #endif 479 { 480 /* everything will be done when the queueing scheme is attached. */ 481 return 0; 482 } 483 484 int 485 rioclose(dev, flag, fmt, p) 486 dev_t dev; 487 int flag, fmt; 488 #if (__FreeBSD_version > 500000) 489 struct thread *p; 490 #else 491 struct proc *p; 492 #endif 493 { 494 rio_queue_t *rqp; 495 int err, error = 0; 496 497 while ((rqp = rio_list) != NULL) { 498 /* destroy all */ 499 err = rio_detach(rqp); 500 if (err != 0 && error == 0) 501 error = err; 502 } 503 504 return error; 505 } 506 507 int 508 rioioctl(dev, cmd, addr, flag, p) 509 dev_t dev; 510 ioctlcmd_t cmd; 511 caddr_t addr; 512 int flag; 513 #if (__FreeBSD_version > 500000) 514 struct thread *p; 515 #else 516 struct proc *p; 517 #endif 518 { 519 rio_queue_t *rqp; 520 struct rio_interface *ifacep; 521 struct ifnet *ifp; 522 int error = 0; 523 524 /* check super-user privilege */ 525 switch (cmd) { 526 case RIO_GETSTATS: 527 break; 528 default: 529 #if (__FreeBSD_version > 700000) 530 if ((error = priv_check(p, PRIV_ALTQ_MANAGE)) != 0) 531 return (error); 532 #elsif (__FreeBSD_version > 400000) 533 if ((error = suser(p)) != 0) 534 return (error); 535 #else 536 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 537 return (error); 538 #endif 539 break; 540 } 541 542 switch (cmd) { 543 544 case RIO_ENABLE: 545 ifacep = (struct rio_interface *)addr; 546 if ((rqp = altq_lookup(ifacep->rio_ifname, ALTQT_RIO)) == NULL) { 547 error = EBADF; 548 break; 549 } 550 error = altq_enable(rqp->rq_ifq); 551 break; 552 553 case RIO_DISABLE: 554 ifacep = (struct rio_interface *)addr; 555 if ((rqp = altq_lookup(ifacep->rio_ifname, ALTQT_RIO)) == NULL) { 556 error = EBADF; 557 break; 558 } 559 error = altq_disable(rqp->rq_ifq); 560 break; 561 562 case RIO_IF_ATTACH: 563 ifp = ifunit(((struct rio_interface *)addr)->rio_ifname); 564 if (ifp == NULL) { 565 error = ENXIO; 566 break; 567 } 568 569 /* allocate and initialize rio_queue_t */ 570 rqp = malloc(sizeof(rio_queue_t), M_DEVBUF, M_WAITOK); 571 if (rqp == NULL) { 572 error = ENOMEM; 573 break; 574 } 575 bzero(rqp, sizeof(rio_queue_t)); 576 577 rqp->rq_q = malloc(sizeof(class_queue_t), 578 M_DEVBUF, M_WAITOK); 579 if (rqp->rq_q == NULL) { 580 free(rqp, M_DEVBUF); 581 error = ENOMEM; 582 break; 583 } 584 bzero(rqp->rq_q, sizeof(class_queue_t)); 585 586 rqp->rq_rio = rio_alloc(0, NULL, 0, 0); 587 if (rqp->rq_rio == NULL) { 588 free(rqp->rq_q, M_DEVBUF); 589 free(rqp, M_DEVBUF); 590 error = ENOMEM; 591 break; 592 } 593 594 rqp->rq_ifq = &ifp->if_snd; 595 qtail(rqp->rq_q) = NULL; 596 qlen(rqp->rq_q) = 0; 597 qlimit(rqp->rq_q) = RIO_LIMIT; 598 qtype(rqp->rq_q) = Q_RIO; 599 600 /* 601 * set RIO to this ifnet structure. 602 */ 603 error = altq_attach(rqp->rq_ifq, ALTQT_RIO, rqp, 604 rio_enqueue, rio_dequeue, rio_request, 605 NULL, NULL); 606 if (error) { 607 rio_destroy(rqp->rq_rio); 608 free(rqp->rq_q, M_DEVBUF); 609 free(rqp, M_DEVBUF); 610 break; 611 } 612 613 /* add this state to the rio list */ 614 rqp->rq_next = rio_list; 615 rio_list = rqp; 616 break; 617 618 case RIO_IF_DETACH: 619 ifacep = (struct rio_interface *)addr; 620 if ((rqp = altq_lookup(ifacep->rio_ifname, ALTQT_RIO)) == NULL) { 621 error = EBADF; 622 break; 623 } 624 error = rio_detach(rqp); 625 break; 626 627 case RIO_GETSTATS: 628 do { 629 struct rio_stats *q_stats; 630 rio_t *rp; 631 int i; 632 633 q_stats = (struct rio_stats *)addr; 634 if ((rqp = altq_lookup(q_stats->iface.rio_ifname, 635 ALTQT_RIO)) == NULL) { 636 error = EBADF; 637 break; 638 } 639 640 rp = rqp->rq_rio; 641 642 q_stats->q_limit = qlimit(rqp->rq_q); 643 q_stats->weight = rp->rio_weight; 644 q_stats->flags = rp->rio_flags; 645 646 for (i = 0; i < RIO_NDROPPREC; i++) { 647 q_stats->q_len[i] = rp->rio_precstate[i].qlen; 648 bcopy(&rp->q_stats[i], &q_stats->q_stats[i], 649 sizeof(struct redstats)); 650 q_stats->q_stats[i].q_avg = 651 rp->rio_precstate[i].avg >> rp->rio_wshift; 652 653 q_stats->q_params[i].inv_pmax 654 = rp->rio_precstate[i].inv_pmax; 655 q_stats->q_params[i].th_min 656 = rp->rio_precstate[i].th_min; 657 q_stats->q_params[i].th_max 658 = rp->rio_precstate[i].th_max; 659 } 660 } while (/*CONSTCOND*/ 0); 661 break; 662 663 case RIO_CONFIG: 664 do { 665 struct rio_conf *fc; 666 rio_t *new; 667 int s, limit, i; 668 669 fc = (struct rio_conf *)addr; 670 if ((rqp = altq_lookup(fc->iface.rio_ifname, 671 ALTQT_RIO)) == NULL) { 672 error = EBADF; 673 break; 674 } 675 676 new = rio_alloc(fc->rio_weight, &fc->q_params[0], 677 fc->rio_flags, fc->rio_pkttime); 678 if (new == NULL) { 679 error = ENOMEM; 680 break; 681 } 682 683 s = splnet(); 684 _flushq(rqp->rq_q); 685 limit = fc->rio_limit; 686 if (limit < fc->q_params[RIO_NDROPPREC-1].th_max) 687 limit = fc->q_params[RIO_NDROPPREC-1].th_max; 688 qlimit(rqp->rq_q) = limit; 689 690 rio_destroy(rqp->rq_rio); 691 rqp->rq_rio = new; 692 693 splx(s); 694 695 /* write back new values */ 696 fc->rio_limit = limit; 697 for (i = 0; i < RIO_NDROPPREC; i++) { 698 fc->q_params[i].inv_pmax = 699 rqp->rq_rio->rio_precstate[i].inv_pmax; 700 fc->q_params[i].th_min = 701 rqp->rq_rio->rio_precstate[i].th_min; 702 fc->q_params[i].th_max = 703 rqp->rq_rio->rio_precstate[i].th_max; 704 } 705 } while (/*CONSTCOND*/ 0); 706 break; 707 708 case RIO_SETDEFAULTS: 709 do { 710 struct redparams *rp; 711 int i; 712 713 rp = (struct redparams *)addr; 714 for (i = 0; i < RIO_NDROPPREC; i++) 715 default_rio_params[i] = rp[i]; 716 } while (/*CONSTCOND*/ 0); 717 break; 718 719 default: 720 error = EINVAL; 721 break; 722 } 723 724 return error; 725 } 726 727 static int 728 rio_detach(rqp) 729 rio_queue_t *rqp; 730 { 731 rio_queue_t *tmp; 732 int error = 0; 733 734 if (ALTQ_IS_ENABLED(rqp->rq_ifq)) 735 altq_disable(rqp->rq_ifq); 736 737 if ((error = altq_detach(rqp->rq_ifq))) 738 return (error); 739 740 if (rio_list == rqp) 741 rio_list = rqp->rq_next; 742 else { 743 for (tmp = rio_list; tmp != NULL; tmp = tmp->rq_next) 744 if (tmp->rq_next == rqp) { 745 tmp->rq_next = rqp->rq_next; 746 break; 747 } 748 if (tmp == NULL) 749 printf("rio_detach: no state found in rio_list!\n"); 750 } 751 752 rio_destroy(rqp->rq_rio); 753 free(rqp->rq_q, M_DEVBUF); 754 free(rqp, M_DEVBUF); 755 return (error); 756 } 757 758 /* 759 * rio support routines 760 */ 761 static int 762 rio_request(ifq, req, arg) 763 struct ifaltq *ifq; 764 int req; 765 void *arg; 766 { 767 rio_queue_t *rqp = (rio_queue_t *)ifq->altq_disc; 768 769 IFQ_LOCK_ASSERT(ifq); 770 771 switch (req) { 772 case ALTRQ_PURGE: 773 _flushq(rqp->rq_q); 774 if (ALTQ_IS_ENABLED(ifq)) 775 ifq->ifq_len = 0; 776 break; 777 } 778 return (0); 779 } 780 781 /* 782 * enqueue routine: 783 * 784 * returns: 0 when successfully queued. 785 * ENOBUFS when drop occurs. 786 */ 787 static int 788 rio_enqueue(ifq, m, pktattr) 789 struct ifaltq *ifq; 790 struct mbuf *m; 791 struct altq_pktattr *pktattr; 792 { 793 rio_queue_t *rqp = (rio_queue_t *)ifq->altq_disc; 794 int error = 0; 795 796 IFQ_LOCK_ASSERT(ifq); 797 798 if (rio_addq(rqp->rq_rio, rqp->rq_q, m, pktattr) == 0) 799 ifq->ifq_len++; 800 else 801 error = ENOBUFS; 802 return error; 803 } 804 805 /* 806 * dequeue routine: 807 * must be called in splimp. 808 * 809 * returns: mbuf dequeued. 810 * NULL when no packet is available in the queue. 811 */ 812 813 static struct mbuf * 814 rio_dequeue(ifq, op) 815 struct ifaltq *ifq; 816 int op; 817 { 818 rio_queue_t *rqp = (rio_queue_t *)ifq->altq_disc; 819 struct mbuf *m = NULL; 820 821 IFQ_LOCK_ASSERT(ifq); 822 823 if (op == ALTDQ_POLL) 824 return qhead(rqp->rq_q); 825 826 m = rio_getq(rqp->rq_rio, rqp->rq_q); 827 if (m != NULL) 828 ifq->ifq_len--; 829 return m; 830 } 831 832 #ifdef KLD_MODULE 833 834 static struct altqsw rio_sw = 835 {"rio", rioopen, rioclose, rioioctl}; 836 837 ALTQ_MODULE(altq_rio, ALTQT_RIO, &rio_sw); 838 MODULE_VERSION(altq_rio, 1); 839 MODULE_DEPEND(altq_rio, altq_red, 1, 1, 1); 840 841 #endif /* KLD_MODULE */ 842 #endif /* ALTQ3_COMPAT */ 843 844 #endif /* ALTQ_RIO */ 845