1 /* $NetBSD: altq_priq.c,v 1.13 2006/07/21 16:48:45 ad Exp $ */ 2 /* $KAME: altq_priq.c,v 1.2 2001/10/26 04:56:11 kjc Exp $ */ 3 /* 4 * Copyright (C) 2000 5 * Sony Computer Science Laboratories Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 /* 29 * priority queue 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: altq_priq.c,v 1.13 2006/07/21 16:48:45 ad Exp $"); 34 35 #if defined(__FreeBSD__) || defined(__NetBSD__) 36 #include "opt_altq.h" 37 #if (__FreeBSD__ != 2) 38 #include "opt_inet.h" 39 #ifdef __FreeBSD__ 40 #include "opt_inet6.h" 41 #endif 42 #endif 43 #endif /* __FreeBSD__ || __NetBSD__ */ 44 45 #ifdef ALTQ_PRIQ /* priq is enabled by ALTQ_PRIQ option in opt_altq.h */ 46 47 #include <sys/param.h> 48 #include <sys/malloc.h> 49 #include <sys/mbuf.h> 50 #include <sys/socket.h> 51 #include <sys/sockio.h> 52 #include <sys/systm.h> 53 #include <sys/proc.h> 54 #include <sys/errno.h> 55 #include <sys/kernel.h> 56 #include <sys/queue.h> 57 #include <sys/kauth.h> 58 59 #include <net/if.h> 60 #include <net/if_types.h> 61 62 #include <altq/altq.h> 63 #include <altq/altq_conf.h> 64 #include <altq/altq_priq.h> 65 66 /* 67 * function prototypes 68 */ 69 static struct priq_if *priq_attach __P((struct ifaltq *, u_int)); 70 static int priq_detach __P((struct priq_if *)); 71 static int priq_clear_interface __P((struct priq_if *)); 72 static int priq_request __P((struct ifaltq *, int, void *)); 73 static void priq_purge __P((struct priq_if *)); 74 static struct priq_class *priq_class_create __P((struct priq_if *, 75 int, int, int)); 76 static int priq_class_destroy __P((struct priq_class *)); 77 static int priq_enqueue __P((struct ifaltq *, struct mbuf *, 78 struct altq_pktattr *)); 79 static struct mbuf *priq_dequeue __P((struct ifaltq *, int)); 80 81 static int priq_addq __P((struct priq_class *, struct mbuf *)); 82 static struct mbuf *priq_getq __P((struct priq_class *)); 83 static struct mbuf *priq_pollq __P((struct priq_class *)); 84 static void priq_purgeq __P((struct priq_class *)); 85 86 int priqopen __P((dev_t, int, int, struct lwp *)); 87 int priqclose __P((dev_t, int, int, struct lwp *)); 88 int priqioctl __P((dev_t, ioctlcmd_t, caddr_t, int, struct lwp *)); 89 static int priqcmd_if_attach __P((struct priq_interface *)); 90 static int priqcmd_if_detach __P((struct priq_interface *)); 91 static int priqcmd_add_class __P((struct priq_add_class *)); 92 static int priqcmd_delete_class __P((struct priq_delete_class *)); 93 static int priqcmd_modify_class __P((struct priq_modify_class *)); 94 static int priqcmd_add_filter __P((struct priq_add_filter *)); 95 static int priqcmd_delete_filter __P((struct priq_delete_filter *)); 96 static int priqcmd_class_stats __P((struct priq_class_stats *)); 97 static void get_class_stats __P((struct priq_basic_class_stats *, 98 struct priq_class *)); 99 static struct priq_class *clh_to_clp __P((struct priq_if *, u_long)); 100 static u_long clp_to_clh __P((struct priq_class *)); 101 102 /* pif_list keeps all priq_if's allocated. */ 103 static struct priq_if *pif_list = NULL; 104 105 static struct priq_if * 106 priq_attach(ifq, bandwidth) 107 struct ifaltq *ifq; 108 u_int bandwidth; 109 { 110 struct priq_if *pif; 111 112 pif = malloc(sizeof(struct priq_if), M_DEVBUF, M_WAITOK|M_ZERO); 113 if (pif == NULL) 114 return (NULL); 115 pif->pif_bandwidth = bandwidth; 116 pif->pif_maxpri = -1; 117 pif->pif_ifq = ifq; 118 119 /* add this state to the priq list */ 120 pif->pif_next = pif_list; 121 pif_list = pif; 122 123 return (pif); 124 } 125 126 static int 127 priq_detach(pif) 128 struct priq_if *pif; 129 { 130 (void)priq_clear_interface(pif); 131 132 /* remove this interface from the pif list */ 133 if (pif_list == pif) 134 pif_list = pif->pif_next; 135 else { 136 struct priq_if *p; 137 138 for (p = pif_list; p != NULL; p = p->pif_next) 139 if (p->pif_next == pif) { 140 p->pif_next = pif->pif_next; 141 break; 142 } 143 ASSERT(p != NULL); 144 } 145 146 free(pif, M_DEVBUF); 147 return (0); 148 } 149 150 /* 151 * bring the interface back to the initial state by discarding 152 * all the filters and classes. 153 */ 154 static int 155 priq_clear_interface(pif) 156 struct priq_if *pif; 157 { 158 struct priq_class *cl; 159 int pri; 160 161 /* free the filters for this interface */ 162 acc_discard_filters(&pif->pif_classifier, NULL, 1); 163 164 /* clear out the classes */ 165 for (pri = 0; pri <= pif->pif_maxpri; pri++) 166 if ((cl = pif->pif_classes[pri]) != NULL) 167 priq_class_destroy(cl); 168 169 return (0); 170 } 171 172 static int 173 priq_request(ifq, req, arg) 174 struct ifaltq *ifq; 175 int req; 176 void *arg; 177 { 178 struct priq_if *pif = (struct priq_if *)ifq->altq_disc; 179 180 switch (req) { 181 case ALTRQ_PURGE: 182 priq_purge(pif); 183 break; 184 } 185 return (0); 186 } 187 188 /* discard all the queued packets on the interface */ 189 static void 190 priq_purge(pif) 191 struct priq_if *pif; 192 { 193 struct priq_class *cl; 194 int pri; 195 196 for (pri = 0; pri <= pif->pif_maxpri; pri++) { 197 if ((cl = pif->pif_classes[pri]) != NULL && !qempty(cl->cl_q)) 198 priq_purgeq(cl); 199 } 200 if (ALTQ_IS_ENABLED(pif->pif_ifq)) 201 pif->pif_ifq->ifq_len = 0; 202 } 203 204 static struct priq_class * 205 priq_class_create(pif, pri, qlimit, flags) 206 struct priq_if *pif; 207 int pri, qlimit, flags; 208 { 209 struct priq_class *cl; 210 int s; 211 212 #ifndef ALTQ_RED 213 if (flags & PRCF_RED) { 214 printf("priq_class_create: RED not configured for PRIQ!\n"); 215 return (NULL); 216 } 217 #endif 218 219 if ((cl = pif->pif_classes[pri]) != NULL) { 220 /* modify the class instead of creating a new one */ 221 s = splnet(); 222 if (!qempty(cl->cl_q)) 223 priq_purgeq(cl); 224 splx(s); 225 #ifdef ALTQ_RIO 226 if (q_is_rio(cl->cl_q)) 227 rio_destroy((rio_t *)cl->cl_red); 228 #endif 229 #ifdef ALTQ_RED 230 if (q_is_red(cl->cl_q)) 231 red_destroy(cl->cl_red); 232 #endif 233 } else { 234 cl = malloc(sizeof(struct priq_class), M_DEVBUF, 235 M_WAITOK|M_ZERO); 236 if (cl == NULL) 237 return (NULL); 238 239 cl->cl_q = malloc(sizeof(class_queue_t), M_DEVBUF, 240 M_WAITOK|M_ZERO); 241 if (cl->cl_q == NULL) 242 goto err_ret; 243 } 244 245 pif->pif_classes[pri] = cl; 246 if (flags & PRCF_DEFAULTCLASS) 247 pif->pif_default = cl; 248 if (qlimit == 0) 249 qlimit = 50; /* use default */ 250 qlimit(cl->cl_q) = qlimit; 251 qtype(cl->cl_q) = Q_DROPTAIL; 252 qlen(cl->cl_q) = 0; 253 cl->cl_flags = flags; 254 cl->cl_pri = pri; 255 if (pri > pif->pif_maxpri) 256 pif->pif_maxpri = pri; 257 cl->cl_pif = pif; 258 cl->cl_handle = (u_long)cl; /* XXX: just a pointer to this class */ 259 260 #ifdef ALTQ_RED 261 if (flags & (PRCF_RED|PRCF_RIO)) { 262 int red_flags, red_pkttime; 263 264 red_flags = 0; 265 if (flags & PRCF_ECN) 266 red_flags |= REDF_ECN; 267 #ifdef ALTQ_RIO 268 if (flags & PRCF_CLEARDSCP) 269 red_flags |= RIOF_CLEARDSCP; 270 #endif 271 if (pif->pif_bandwidth < 8) 272 red_pkttime = 1000 * 1000 * 1000; /* 1 sec */ 273 else 274 red_pkttime = (int64_t)pif->pif_ifq->altq_ifp->if_mtu 275 * 1000 * 1000 * 1000 / (pif->pif_bandwidth / 8); 276 #ifdef ALTQ_RIO 277 if (flags & PRCF_RIO) { 278 cl->cl_red = (red_t *)rio_alloc(0, NULL, 279 red_flags, red_pkttime); 280 if (cl->cl_red != NULL) 281 qtype(cl->cl_q) = Q_RIO; 282 } else 283 #endif 284 if (flags & PRCF_RED) { 285 cl->cl_red = red_alloc(0, 0, 0, 0, 286 red_flags, red_pkttime); 287 if (cl->cl_red != NULL) 288 qtype(cl->cl_q) = Q_RED; 289 } 290 } 291 #endif /* ALTQ_RED */ 292 293 return (cl); 294 295 err_ret: 296 if (cl->cl_red != NULL) { 297 #ifdef ALTQ_RIO 298 if (q_is_rio(cl->cl_q)) 299 rio_destroy((rio_t *)cl->cl_red); 300 #endif 301 #ifdef ALTQ_RED 302 if (q_is_red(cl->cl_q)) 303 red_destroy(cl->cl_red); 304 #endif 305 } 306 if (cl->cl_q != NULL) 307 free(cl->cl_q, M_DEVBUF); 308 free(cl, M_DEVBUF); 309 return (NULL); 310 } 311 312 static int 313 priq_class_destroy(cl) 314 struct priq_class *cl; 315 { 316 struct priq_if *pif; 317 int s, pri; 318 319 s = splnet(); 320 321 /* delete filters referencing to this class */ 322 acc_discard_filters(&cl->cl_pif->pif_classifier, cl, 0); 323 324 if (!qempty(cl->cl_q)) 325 priq_purgeq(cl); 326 327 pif = cl->cl_pif; 328 pif->pif_classes[cl->cl_pri] = NULL; 329 if (pif->pif_maxpri == cl->cl_pri) { 330 for (pri = cl->cl_pri; pri >= 0; pri--) 331 if (pif->pif_classes[pri] != NULL) { 332 pif->pif_maxpri = pri; 333 break; 334 } 335 if (pri < 0) 336 pif->pif_maxpri = -1; 337 } 338 splx(s); 339 340 if (cl->cl_red != NULL) { 341 #ifdef ALTQ_RIO 342 if (q_is_rio(cl->cl_q)) 343 rio_destroy((rio_t *)cl->cl_red); 344 #endif 345 #ifdef ALTQ_RED 346 if (q_is_red(cl->cl_q)) 347 red_destroy(cl->cl_red); 348 #endif 349 } 350 free(cl->cl_q, M_DEVBUF); 351 free(cl, M_DEVBUF); 352 return (0); 353 } 354 355 /* 356 * priq_enqueue is an enqueue function to be registered to 357 * (*altq_enqueue) in struct ifaltq. 358 */ 359 static int 360 priq_enqueue(ifq, m, pktattr) 361 struct ifaltq *ifq; 362 struct mbuf *m; 363 struct altq_pktattr *pktattr; 364 { 365 struct priq_if *pif = (struct priq_if *)ifq->altq_disc; 366 struct priq_class *cl; 367 int len; 368 369 /* grab class set by classifier */ 370 if (pktattr == NULL || (cl = pktattr->pattr_class) == NULL) 371 cl = pif->pif_default; 372 cl->cl_pktattr = pktattr; /* save proto hdr used by ECN */ 373 374 len = m_pktlen(m); 375 if (priq_addq(cl, m) != 0) { 376 /* drop occurred. mbuf was freed in priq_addq. */ 377 PKTCNTR_ADD(&cl->cl_dropcnt, len); 378 return (ENOBUFS); 379 } 380 IFQ_INC_LEN(ifq); 381 382 /* successfully queued. */ 383 return (0); 384 } 385 386 /* 387 * priq_dequeue is a dequeue function to be registered to 388 * (*altq_dequeue) in struct ifaltq. 389 * 390 * note: ALTDQ_POLL returns the next packet without removing the packet 391 * from the queue. ALTDQ_REMOVE is a normal dequeue operation. 392 * ALTDQ_REMOVE must return the same packet if called immediately 393 * after ALTDQ_POLL. 394 */ 395 static struct mbuf * 396 priq_dequeue(ifq, op) 397 struct ifaltq *ifq; 398 int op; 399 { 400 struct priq_if *pif = (struct priq_if *)ifq->altq_disc; 401 struct priq_class *cl; 402 struct mbuf *m; 403 int pri; 404 405 if (IFQ_IS_EMPTY(ifq)) 406 /* no packet in the queue */ 407 return (NULL); 408 409 for (pri = pif->pif_maxpri; pri >= 0; pri--) { 410 if ((cl = pif->pif_classes[pri]) != NULL && 411 !qempty(cl->cl_q)) { 412 if (op == ALTDQ_POLL) 413 return (priq_pollq(cl)); 414 415 m = priq_getq(cl); 416 if (m != NULL) { 417 IFQ_DEC_LEN(ifq); 418 if (qempty(cl->cl_q)) 419 cl->cl_period++; 420 PKTCNTR_ADD(&cl->cl_xmitcnt, m_pktlen(m)); 421 } 422 return (m); 423 } 424 } 425 return (NULL); 426 } 427 428 static int 429 priq_addq(cl, m) 430 struct priq_class *cl; 431 struct mbuf *m; 432 { 433 434 #ifdef ALTQ_RIO 435 if (q_is_rio(cl->cl_q)) 436 return rio_addq((rio_t *)cl->cl_red, cl->cl_q, m, 437 cl->cl_pktattr); 438 #endif 439 #ifdef ALTQ_RED 440 if (q_is_red(cl->cl_q)) 441 return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr); 442 #endif 443 if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) { 444 m_freem(m); 445 return (-1); 446 } 447 448 if (cl->cl_flags & PRCF_CLEARDSCP) 449 write_dsfield(m, cl->cl_pktattr, 0); 450 451 _addq(cl->cl_q, m); 452 453 return (0); 454 } 455 456 static struct mbuf * 457 priq_getq(cl) 458 struct priq_class *cl; 459 { 460 #ifdef ALTQ_RIO 461 if (q_is_rio(cl->cl_q)) 462 return rio_getq((rio_t *)cl->cl_red, cl->cl_q); 463 #endif 464 #ifdef ALTQ_RED 465 if (q_is_red(cl->cl_q)) 466 return red_getq(cl->cl_red, cl->cl_q); 467 #endif 468 return _getq(cl->cl_q); 469 } 470 471 static struct mbuf * 472 priq_pollq(cl) 473 struct priq_class *cl; 474 { 475 return qhead(cl->cl_q); 476 } 477 478 static void 479 priq_purgeq(cl) 480 struct priq_class *cl; 481 { 482 struct mbuf *m; 483 484 if (qempty(cl->cl_q)) 485 return; 486 487 while ((m = _getq(cl->cl_q)) != NULL) { 488 PKTCNTR_ADD(&cl->cl_dropcnt, m_pktlen(m)); 489 m_freem(m); 490 } 491 ASSERT(qlen(cl->cl_q) == 0); 492 } 493 494 /* 495 * priq device interface 496 */ 497 int 498 priqopen(dev, flag, fmt, l) 499 dev_t dev; 500 int flag, fmt; 501 struct lwp *l; 502 { 503 /* everything will be done when the queueing scheme is attached. */ 504 return 0; 505 } 506 507 int 508 priqclose(dev, flag, fmt, l) 509 dev_t dev; 510 int flag, fmt; 511 struct lwp *l; 512 { 513 struct priq_if *pif; 514 int err, error = 0; 515 516 while ((pif = pif_list) != NULL) { 517 /* destroy all */ 518 if (ALTQ_IS_ENABLED(pif->pif_ifq)) 519 altq_disable(pif->pif_ifq); 520 521 err = altq_detach(pif->pif_ifq); 522 if (err == 0) 523 err = priq_detach(pif); 524 if (err != 0 && error == 0) 525 error = err; 526 } 527 528 return error; 529 } 530 531 int 532 priqioctl(dev, cmd, addr, flag, l) 533 dev_t dev; 534 ioctlcmd_t cmd; 535 caddr_t addr; 536 int flag; 537 struct lwp *l; 538 { 539 struct priq_if *pif; 540 struct priq_interface *ifacep; 541 int error = 0; 542 543 /* check super-user privilege */ 544 switch (cmd) { 545 case PRIQ_GETSTATS: 546 break; 547 default: 548 #if (__FreeBSD_version > 400000) 549 if ((error = suser(p)) != 0) 550 return (error); 551 #else 552 if ((error = kauth_authorize_generic(l->l_cred, 553 KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0) 554 return (error); 555 #endif 556 break; 557 } 558 559 switch (cmd) { 560 561 case PRIQ_IF_ATTACH: 562 error = priqcmd_if_attach((struct priq_interface *)addr); 563 break; 564 565 case PRIQ_IF_DETACH: 566 error = priqcmd_if_detach((struct priq_interface *)addr); 567 break; 568 569 case PRIQ_ENABLE: 570 case PRIQ_DISABLE: 571 case PRIQ_CLEAR: 572 ifacep = (struct priq_interface *)addr; 573 if ((pif = altq_lookup(ifacep->ifname, 574 ALTQT_PRIQ)) == NULL) { 575 error = EBADF; 576 break; 577 } 578 579 switch (cmd) { 580 case PRIQ_ENABLE: 581 if (pif->pif_default == NULL) { 582 #if 1 583 printf("priq: no default class\n"); 584 #endif 585 error = EINVAL; 586 break; 587 } 588 error = altq_enable(pif->pif_ifq); 589 break; 590 591 case PRIQ_DISABLE: 592 error = altq_disable(pif->pif_ifq); 593 break; 594 595 case PRIQ_CLEAR: 596 priq_clear_interface(pif); 597 break; 598 } 599 break; 600 601 case PRIQ_ADD_CLASS: 602 error = priqcmd_add_class((struct priq_add_class *)addr); 603 break; 604 605 case PRIQ_DEL_CLASS: 606 error = priqcmd_delete_class((struct priq_delete_class *)addr); 607 break; 608 609 case PRIQ_MOD_CLASS: 610 error = priqcmd_modify_class((struct priq_modify_class *)addr); 611 break; 612 613 case PRIQ_ADD_FILTER: 614 error = priqcmd_add_filter((struct priq_add_filter *)addr); 615 break; 616 617 case PRIQ_DEL_FILTER: 618 error = priqcmd_delete_filter((struct priq_delete_filter *)addr); 619 break; 620 621 case PRIQ_GETSTATS: 622 error = priqcmd_class_stats((struct priq_class_stats *)addr); 623 break; 624 625 default: 626 error = EINVAL; 627 break; 628 } 629 return error; 630 } 631 632 static int 633 priqcmd_if_attach(ap) 634 struct priq_interface *ap; 635 { 636 struct priq_if *pif; 637 struct ifnet *ifp; 638 int error; 639 640 if ((ifp = ifunit(ap->ifname)) == NULL) 641 return (ENXIO); 642 643 if ((pif = priq_attach(&ifp->if_snd, ap->arg)) == NULL) 644 return (ENOMEM); 645 646 /* 647 * set PRIQ to this ifnet structure. 648 */ 649 if ((error = altq_attach(&ifp->if_snd, ALTQT_PRIQ, pif, 650 priq_enqueue, priq_dequeue, priq_request, 651 &pif->pif_classifier, acc_classify)) != 0) 652 (void)priq_detach(pif); 653 654 return (error); 655 } 656 657 static int 658 priqcmd_if_detach(ap) 659 struct priq_interface *ap; 660 { 661 struct priq_if *pif; 662 int error; 663 664 if ((pif = altq_lookup(ap->ifname, ALTQT_PRIQ)) == NULL) 665 return (EBADF); 666 667 if (ALTQ_IS_ENABLED(pif->pif_ifq)) 668 altq_disable(pif->pif_ifq); 669 670 if ((error = altq_detach(pif->pif_ifq))) 671 return (error); 672 673 return priq_detach(pif); 674 } 675 676 static int 677 priqcmd_add_class(ap) 678 struct priq_add_class *ap; 679 { 680 struct priq_if *pif; 681 struct priq_class *cl; 682 683 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL) 684 return (EBADF); 685 686 if (ap->pri < 0 || ap->pri >= PRIQ_MAXPRI) 687 return (EINVAL); 688 689 if ((cl = priq_class_create(pif, ap->pri, 690 ap->qlimit, ap->flags)) == NULL) 691 return (ENOMEM); 692 693 /* return a class handle to the user */ 694 ap->class_handle = clp_to_clh(cl); 695 return (0); 696 } 697 698 static int 699 priqcmd_delete_class(ap) 700 struct priq_delete_class *ap; 701 { 702 struct priq_if *pif; 703 struct priq_class *cl; 704 705 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL) 706 return (EBADF); 707 708 if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL) 709 return (EINVAL); 710 711 return priq_class_destroy(cl); 712 } 713 714 static int 715 priqcmd_modify_class(ap) 716 struct priq_modify_class *ap; 717 { 718 struct priq_if *pif; 719 struct priq_class *cl; 720 721 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL) 722 return (EBADF); 723 724 if (ap->pri < 0 || ap->pri >= PRIQ_MAXPRI) 725 return (EINVAL); 726 727 if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL) 728 return (EINVAL); 729 730 /* 731 * if priority is changed, move the class to the new priority 732 */ 733 if (pif->pif_classes[ap->pri] != cl) { 734 if (pif->pif_classes[ap->pri] != NULL) 735 return (EEXIST); 736 pif->pif_classes[cl->cl_pri] = NULL; 737 pif->pif_classes[ap->pri] = cl; 738 cl->cl_pri = ap->pri; 739 } 740 741 /* call priq_class_create to change class parameters */ 742 if ((cl = priq_class_create(pif, ap->pri, 743 ap->qlimit, ap->flags)) == NULL) 744 return (ENOMEM); 745 return 0; 746 } 747 748 static int 749 priqcmd_add_filter(ap) 750 struct priq_add_filter *ap; 751 { 752 struct priq_if *pif; 753 struct priq_class *cl; 754 755 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL) 756 return (EBADF); 757 758 if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL) 759 return (EINVAL); 760 761 return acc_add_filter(&pif->pif_classifier, &ap->filter, 762 cl, &ap->filter_handle); 763 } 764 765 static int 766 priqcmd_delete_filter(ap) 767 struct priq_delete_filter *ap; 768 { 769 struct priq_if *pif; 770 771 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL) 772 return (EBADF); 773 774 return acc_delete_filter(&pif->pif_classifier, 775 ap->filter_handle); 776 } 777 778 static int 779 priqcmd_class_stats(ap) 780 struct priq_class_stats *ap; 781 { 782 struct priq_if *pif; 783 struct priq_class *cl; 784 struct priq_basic_class_stats stats, *usp; 785 int pri, error; 786 787 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL) 788 return (EBADF); 789 790 ap->maxpri = pif->pif_maxpri; 791 792 /* then, read the next N classes in the tree */ 793 usp = ap->stats; 794 for (pri = 0; pri <= pif->pif_maxpri; pri++) { 795 cl = pif->pif_classes[pri]; 796 if (cl != NULL) 797 get_class_stats(&stats, cl); 798 else 799 (void)memset(&stats, 0, sizeof(stats)); 800 if ((error = copyout((caddr_t)&stats, (caddr_t)usp++, 801 sizeof(stats))) != 0) 802 return (error); 803 } 804 return (0); 805 } 806 807 static void get_class_stats(sp, cl) 808 struct priq_basic_class_stats *sp; 809 struct priq_class *cl; 810 { 811 sp->class_handle = clp_to_clh(cl); 812 813 sp->qlength = qlen(cl->cl_q); 814 sp->period = cl->cl_period; 815 sp->xmitcnt = cl->cl_xmitcnt; 816 sp->dropcnt = cl->cl_dropcnt; 817 818 sp->qtype = qtype(cl->cl_q); 819 #ifdef ALTQ_RED 820 if (q_is_red(cl->cl_q)) 821 red_getstats(cl->cl_red, &sp->red[0]); 822 #endif 823 #ifdef ALTQ_RIO 824 if (q_is_rio(cl->cl_q)) 825 rio_getstats((rio_t *)cl->cl_red, &sp->red[0]); 826 #endif 827 828 } 829 830 /* convert a class handle to the corresponding class pointer */ 831 static struct priq_class * 832 clh_to_clp(pif, chandle) 833 struct priq_if *pif; 834 u_long chandle; 835 { 836 struct priq_class *cl; 837 838 cl = (struct priq_class *)chandle; 839 if (chandle != ALIGN(cl)) { 840 #if 1 841 printf("clh_to_cl: unaligned pointer %p\n", cl); 842 #endif 843 return (NULL); 844 } 845 846 if (cl == NULL || cl->cl_handle != chandle || cl->cl_pif != pif) 847 return (NULL); 848 return (cl); 849 } 850 851 /* convert a class pointer to the corresponding class handle */ 852 static u_long 853 clp_to_clh(cl) 854 struct priq_class *cl; 855 { 856 return (cl->cl_handle); 857 } 858 859 #ifdef KLD_MODULE 860 861 static struct altqsw priq_sw = 862 {"priq", priqopen, priqclose, priqioctl}; 863 864 ALTQ_MODULE(altq_priq, ALTQT_PRIQ, &priq_sw); 865 866 #endif /* KLD_MODULE */ 867 868 #endif /* ALTQ_PRIQ */ 869