1 /* $NetBSD: altq_priq.c,v 1.5 2001/11/12 23:14:22 lukem 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.5 2001/11/12 23:14:22 lukem 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 58 #include <net/if.h> 59 #include <net/if_types.h> 60 61 #include <altq/altq.h> 62 #include <altq/altq_conf.h> 63 #include <altq/altq_priq.h> 64 65 /* 66 * function prototypes 67 */ 68 static struct priq_if *priq_attach __P((struct ifaltq *, u_int)); 69 static int priq_detach __P((struct priq_if *)); 70 static int priq_clear_interface __P((struct priq_if *)); 71 static int priq_request __P((struct ifaltq *, int, void *)); 72 static void priq_purge __P((struct priq_if *)); 73 static struct priq_class *priq_class_create __P((struct priq_if *, 74 int, int, int)); 75 static int priq_class_destroy __P((struct priq_class *)); 76 static int priq_enqueue __P((struct ifaltq *, struct mbuf *, 77 struct altq_pktattr *)); 78 static struct mbuf *priq_dequeue __P((struct ifaltq *, int)); 79 80 static int priq_addq __P((struct priq_class *, struct mbuf *)); 81 static struct mbuf *priq_getq __P((struct priq_class *)); 82 static struct mbuf *priq_pollq __P((struct priq_class *)); 83 static void priq_purgeq __P((struct priq_class *)); 84 85 int priqopen __P((dev_t, int, int, struct proc *)); 86 int priqclose __P((dev_t, int, int, struct proc *)); 87 int priqioctl __P((dev_t, ioctlcmd_t, caddr_t, int, struct proc *)); 88 static int priqcmd_if_attach __P((struct priq_interface *)); 89 static int priqcmd_if_detach __P((struct priq_interface *)); 90 static int priqcmd_add_class __P((struct priq_add_class *)); 91 static int priqcmd_delete_class __P((struct priq_delete_class *)); 92 static int priqcmd_modify_class __P((struct priq_modify_class *)); 93 static int priqcmd_add_filter __P((struct priq_add_filter *)); 94 static int priqcmd_delete_filter __P((struct priq_delete_filter *)); 95 static int priqcmd_class_stats __P((struct priq_class_stats *)); 96 static void get_class_stats __P((struct class_stats *, struct priq_class *)); 97 static struct priq_class *clh_to_clp __P((struct priq_if *, u_long)); 98 static u_long clp_to_clh __P((struct priq_class *)); 99 100 /* pif_list keeps all priq_if's allocated. */ 101 static struct priq_if *pif_list = NULL; 102 103 static struct priq_if * 104 priq_attach(ifq, bandwidth) 105 struct ifaltq *ifq; 106 u_int bandwidth; 107 { 108 struct priq_if *pif; 109 110 MALLOC(pif, struct priq_if *, sizeof(struct priq_if), 111 M_DEVBUF, M_WAITOK); 112 if (pif == NULL) 113 return (NULL); 114 bzero(pif, sizeof(struct priq_if)); 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 MALLOC(cl, struct priq_class *, sizeof(struct priq_class), 235 M_DEVBUF, M_WAITOK); 236 if (cl == NULL) 237 return (NULL); 238 bzero(cl, sizeof(struct priq_class)); 239 240 MALLOC(cl->cl_q, class_queue_t *, sizeof(class_queue_t), 241 M_DEVBUF, M_WAITOK); 242 if (cl->cl_q == NULL) 243 goto err_ret; 244 bzero(cl->cl_q, sizeof(class_queue_t)); 245 } 246 247 pif->pif_classes[pri] = cl; 248 if (flags & PRCF_DEFAULTCLASS) 249 pif->pif_default = cl; 250 if (qlimit == 0) 251 qlimit = 50; /* use default */ 252 qlimit(cl->cl_q) = qlimit; 253 qtype(cl->cl_q) = Q_DROPTAIL; 254 qlen(cl->cl_q) = 0; 255 cl->cl_flags = flags; 256 cl->cl_pri = pri; 257 if (pri > pif->pif_maxpri) 258 pif->pif_maxpri = pri; 259 cl->cl_pif = pif; 260 cl->cl_handle = (u_long)cl; /* XXX: just a pointer to this class */ 261 262 #ifdef ALTQ_RED 263 if (flags & (PRCF_RED|PRCF_RIO)) { 264 int red_flags, red_pkttime; 265 266 red_flags = 0; 267 if (flags & PRCF_ECN) 268 red_flags |= REDF_ECN; 269 #ifdef ALTQ_RIO 270 if (flags & PRCF_CLEARDSCP) 271 red_flags |= RIOF_CLEARDSCP; 272 #endif 273 if (pif->pif_bandwidth < 8) 274 red_pkttime = 1000 * 1000 * 1000; /* 1 sec */ 275 else 276 red_pkttime = (int64_t)pif->pif_ifq->altq_ifp->if_mtu 277 * 1000 * 1000 * 1000 / (pif->pif_bandwidth / 8); 278 #ifdef ALTQ_RIO 279 if (flags & PRCF_RIO) { 280 cl->cl_red = (red_t *)rio_alloc(0, NULL, 281 red_flags, red_pkttime); 282 if (cl->cl_red != NULL) 283 qtype(cl->cl_q) = Q_RIO; 284 } else 285 #endif 286 if (flags & PRCF_RED) { 287 cl->cl_red = red_alloc(0, 0, 0, 0, 288 red_flags, red_pkttime); 289 if (cl->cl_red != NULL) 290 qtype(cl->cl_q) = Q_RED; 291 } 292 } 293 #endif /* ALTQ_RED */ 294 295 return (cl); 296 297 err_ret: 298 if (cl->cl_red != NULL) { 299 #ifdef ALTQ_RIO 300 if (q_is_rio(cl->cl_q)) 301 rio_destroy((rio_t *)cl->cl_red); 302 #endif 303 #ifdef ALTQ_RED 304 if (q_is_red(cl->cl_q)) 305 red_destroy(cl->cl_red); 306 #endif 307 } 308 if (cl->cl_q != NULL) 309 FREE(cl->cl_q, M_DEVBUF); 310 FREE(cl, M_DEVBUF); 311 return (NULL); 312 } 313 314 static int 315 priq_class_destroy(cl) 316 struct priq_class *cl; 317 { 318 struct priq_if *pif; 319 int s, pri; 320 321 s = splnet(); 322 323 /* delete filters referencing to this class */ 324 acc_discard_filters(&cl->cl_pif->pif_classifier, cl, 0); 325 326 if (!qempty(cl->cl_q)) 327 priq_purgeq(cl); 328 329 pif = cl->cl_pif; 330 pif->pif_classes[cl->cl_pri] = NULL; 331 if (pif->pif_maxpri == cl->cl_pri) { 332 for (pri = cl->cl_pri; pri >= 0; pri--) 333 if (pif->pif_classes[pri] != NULL) { 334 pif->pif_maxpri = pri; 335 break; 336 } 337 if (pri < 0) 338 pif->pif_maxpri = -1; 339 } 340 splx(s); 341 342 if (cl->cl_red != NULL) { 343 #ifdef ALTQ_RIO 344 if (q_is_rio(cl->cl_q)) 345 rio_destroy((rio_t *)cl->cl_red); 346 #endif 347 #ifdef ALTQ_RED 348 if (q_is_red(cl->cl_q)) 349 red_destroy(cl->cl_red); 350 #endif 351 } 352 FREE(cl->cl_q, M_DEVBUF); 353 FREE(cl, M_DEVBUF); 354 return (0); 355 } 356 357 /* 358 * priq_enqueue is an enqueue function to be registered to 359 * (*altq_enqueue) in struct ifaltq. 360 */ 361 static int 362 priq_enqueue(ifq, m, pktattr) 363 struct ifaltq *ifq; 364 struct mbuf *m; 365 struct altq_pktattr *pktattr; 366 { 367 struct priq_if *pif = (struct priq_if *)ifq->altq_disc; 368 struct priq_class *cl; 369 int len; 370 371 /* grab class set by classifier */ 372 if (pktattr == NULL || (cl = pktattr->pattr_class) == NULL) 373 cl = pif->pif_default; 374 cl->cl_pktattr = pktattr; /* save proto hdr used by ECN */ 375 376 len = m_pktlen(m); 377 if (priq_addq(cl, m) != 0) { 378 /* drop occurred. mbuf was freed in priq_addq. */ 379 PKTCNTR_ADD(&cl->cl_dropcnt, len); 380 return (ENOBUFS); 381 } 382 IFQ_INC_LEN(ifq); 383 384 /* successfully queued. */ 385 return (0); 386 } 387 388 /* 389 * priq_dequeue is a dequeue function to be registered to 390 * (*altq_dequeue) in struct ifaltq. 391 * 392 * note: ALTDQ_POLL returns the next packet without removing the packet 393 * from the queue. ALTDQ_REMOVE is a normal dequeue operation. 394 * ALTDQ_REMOVE must return the same packet if called immediately 395 * after ALTDQ_POLL. 396 */ 397 static struct mbuf * 398 priq_dequeue(ifq, op) 399 struct ifaltq *ifq; 400 int op; 401 { 402 struct priq_if *pif = (struct priq_if *)ifq->altq_disc; 403 struct priq_class *cl; 404 struct mbuf *m; 405 int pri; 406 407 if (IFQ_IS_EMPTY(ifq)) 408 /* no packet in the queue */ 409 return (NULL); 410 411 for (pri = pif->pif_maxpri; pri >= 0; pri--) { 412 if ((cl = pif->pif_classes[pri]) != NULL && 413 !qempty(cl->cl_q)) { 414 if (op == ALTDQ_POLL) 415 return (priq_pollq(cl)); 416 417 m = priq_getq(cl); 418 if (m != NULL) { 419 IFQ_DEC_LEN(ifq); 420 if (qempty(cl->cl_q)) 421 cl->cl_period++; 422 PKTCNTR_ADD(&cl->cl_xmitcnt, m_pktlen(m)); 423 } 424 return (m); 425 } 426 } 427 return (NULL); 428 } 429 430 static int 431 priq_addq(cl, m) 432 struct priq_class *cl; 433 struct mbuf *m; 434 { 435 436 #ifdef ALTQ_RIO 437 if (q_is_rio(cl->cl_q)) 438 return rio_addq((rio_t *)cl->cl_red, cl->cl_q, m, 439 cl->cl_pktattr); 440 #endif 441 #ifdef ALTQ_RED 442 if (q_is_red(cl->cl_q)) 443 return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr); 444 #endif 445 if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) { 446 m_freem(m); 447 return (-1); 448 } 449 450 if (cl->cl_flags & PRCF_CLEARDSCP) 451 write_dsfield(m, cl->cl_pktattr, 0); 452 453 _addq(cl->cl_q, m); 454 455 return (0); 456 } 457 458 static struct mbuf * 459 priq_getq(cl) 460 struct priq_class *cl; 461 { 462 #ifdef ALTQ_RIO 463 if (q_is_rio(cl->cl_q)) 464 return rio_getq((rio_t *)cl->cl_red, cl->cl_q); 465 #endif 466 #ifdef ALTQ_RED 467 if (q_is_red(cl->cl_q)) 468 return red_getq(cl->cl_red, cl->cl_q); 469 #endif 470 return _getq(cl->cl_q); 471 } 472 473 static struct mbuf * 474 priq_pollq(cl) 475 struct priq_class *cl; 476 { 477 return qhead(cl->cl_q); 478 } 479 480 static void 481 priq_purgeq(cl) 482 struct priq_class *cl; 483 { 484 struct mbuf *m; 485 486 if (qempty(cl->cl_q)) 487 return; 488 489 while ((m = _getq(cl->cl_q)) != NULL) { 490 PKTCNTR_ADD(&cl->cl_dropcnt, m_pktlen(m)); 491 m_freem(m); 492 } 493 ASSERT(qlen(cl->cl_q) == 0); 494 } 495 496 /* 497 * priq device interface 498 */ 499 int 500 priqopen(dev, flag, fmt, p) 501 dev_t dev; 502 int flag, fmt; 503 struct proc *p; 504 { 505 /* everything will be done when the queueing scheme is attached. */ 506 return 0; 507 } 508 509 int 510 priqclose(dev, flag, fmt, p) 511 dev_t dev; 512 int flag, fmt; 513 struct proc *p; 514 { 515 struct priq_if *pif; 516 int err, error = 0; 517 518 while ((pif = pif_list) != NULL) { 519 /* destroy all */ 520 if (ALTQ_IS_ENABLED(pif->pif_ifq)) 521 altq_disable(pif->pif_ifq); 522 523 err = altq_detach(pif->pif_ifq); 524 if (err == 0) 525 err = priq_detach(pif); 526 if (err != 0 && error == 0) 527 error = err; 528 } 529 530 return error; 531 } 532 533 int 534 priqioctl(dev, cmd, addr, flag, p) 535 dev_t dev; 536 ioctlcmd_t cmd; 537 caddr_t addr; 538 int flag; 539 struct proc *p; 540 { 541 struct priq_if *pif; 542 struct priq_interface *ifacep; 543 int error = 0; 544 545 /* check super-user privilege */ 546 switch (cmd) { 547 case PRIQ_GETSTATS: 548 break; 549 default: 550 #if (__FreeBSD_version > 400000) 551 if ((error = suser(p)) != 0) 552 return (error); 553 #else 554 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 555 return (error); 556 #endif 557 break; 558 } 559 560 switch (cmd) { 561 562 case PRIQ_IF_ATTACH: 563 error = priqcmd_if_attach((struct priq_interface *)addr); 564 break; 565 566 case PRIQ_IF_DETACH: 567 error = priqcmd_if_detach((struct priq_interface *)addr); 568 break; 569 570 case PRIQ_ENABLE: 571 case PRIQ_DISABLE: 572 case PRIQ_CLEAR: 573 ifacep = (struct priq_interface *)addr; 574 if ((pif = altq_lookup(ifacep->ifname, 575 ALTQT_PRIQ)) == NULL) { 576 error = EBADF; 577 break; 578 } 579 580 switch (cmd) { 581 case PRIQ_ENABLE: 582 if (pif->pif_default == NULL) { 583 #if 1 584 printf("priq: no default class\n"); 585 #endif 586 error = EINVAL; 587 break; 588 } 589 error = altq_enable(pif->pif_ifq); 590 break; 591 592 case PRIQ_DISABLE: 593 error = altq_disable(pif->pif_ifq); 594 break; 595 596 case PRIQ_CLEAR: 597 priq_clear_interface(pif); 598 break; 599 } 600 break; 601 602 case PRIQ_ADD_CLASS: 603 error = priqcmd_add_class((struct priq_add_class *)addr); 604 break; 605 606 case PRIQ_DEL_CLASS: 607 error = priqcmd_delete_class((struct priq_delete_class *)addr); 608 break; 609 610 case PRIQ_MOD_CLASS: 611 error = priqcmd_modify_class((struct priq_modify_class *)addr); 612 break; 613 614 case PRIQ_ADD_FILTER: 615 error = priqcmd_add_filter((struct priq_add_filter *)addr); 616 break; 617 618 case PRIQ_DEL_FILTER: 619 error = priqcmd_delete_filter((struct priq_delete_filter *)addr); 620 break; 621 622 case PRIQ_GETSTATS: 623 error = priqcmd_class_stats((struct priq_class_stats *)addr); 624 break; 625 626 default: 627 error = EINVAL; 628 break; 629 } 630 return error; 631 } 632 633 static int 634 priqcmd_if_attach(ap) 635 struct priq_interface *ap; 636 { 637 struct priq_if *pif; 638 struct ifnet *ifp; 639 int error; 640 641 if ((ifp = ifunit(ap->ifname)) == NULL) 642 return (ENXIO); 643 644 if ((pif = priq_attach(&ifp->if_snd, ap->arg)) == NULL) 645 return (ENOMEM); 646 647 /* 648 * set PRIQ to this ifnet structure. 649 */ 650 if ((error = altq_attach(&ifp->if_snd, ALTQT_PRIQ, pif, 651 priq_enqueue, priq_dequeue, priq_request, 652 &pif->pif_classifier, acc_classify)) != 0) 653 (void)priq_detach(pif); 654 655 return (error); 656 } 657 658 static int 659 priqcmd_if_detach(ap) 660 struct priq_interface *ap; 661 { 662 struct priq_if *pif; 663 int error; 664 665 if ((pif = altq_lookup(ap->ifname, ALTQT_PRIQ)) == NULL) 666 return (EBADF); 667 668 if (ALTQ_IS_ENABLED(pif->pif_ifq)) 669 altq_disable(pif->pif_ifq); 670 671 if ((error = altq_detach(pif->pif_ifq))) 672 return (error); 673 674 return priq_detach(pif); 675 } 676 677 static int 678 priqcmd_add_class(ap) 679 struct priq_add_class *ap; 680 { 681 struct priq_if *pif; 682 struct priq_class *cl; 683 684 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL) 685 return (EBADF); 686 687 if (ap->pri < 0 || ap->pri >= PRIQ_MAXPRI) 688 return (EINVAL); 689 690 if ((cl = priq_class_create(pif, ap->pri, 691 ap->qlimit, ap->flags)) == NULL) 692 return (ENOMEM); 693 694 /* return a class handle to the user */ 695 ap->class_handle = clp_to_clh(cl); 696 return (0); 697 } 698 699 static int 700 priqcmd_delete_class(ap) 701 struct priq_delete_class *ap; 702 { 703 struct priq_if *pif; 704 struct priq_class *cl; 705 706 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL) 707 return (EBADF); 708 709 if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL) 710 return (EINVAL); 711 712 return priq_class_destroy(cl); 713 } 714 715 static int 716 priqcmd_modify_class(ap) 717 struct priq_modify_class *ap; 718 { 719 struct priq_if *pif; 720 struct priq_class *cl; 721 722 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL) 723 return (EBADF); 724 725 if (ap->pri < 0 || ap->pri >= PRIQ_MAXPRI) 726 return (EINVAL); 727 728 if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL) 729 return (EINVAL); 730 731 /* 732 * if priority is changed, move the class to the new priority 733 */ 734 if (pif->pif_classes[ap->pri] != cl) { 735 if (pif->pif_classes[ap->pri] != NULL) 736 return (EEXIST); 737 pif->pif_classes[cl->cl_pri] = NULL; 738 pif->pif_classes[ap->pri] = cl; 739 cl->cl_pri = ap->pri; 740 } 741 742 /* call priq_class_create to change class parameters */ 743 if ((cl = priq_class_create(pif, ap->pri, 744 ap->qlimit, ap->flags)) == NULL) 745 return (ENOMEM); 746 return 0; 747 } 748 749 static int 750 priqcmd_add_filter(ap) 751 struct priq_add_filter *ap; 752 { 753 struct priq_if *pif; 754 struct priq_class *cl; 755 756 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL) 757 return (EBADF); 758 759 if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL) 760 return (EINVAL); 761 762 return acc_add_filter(&pif->pif_classifier, &ap->filter, 763 cl, &ap->filter_handle); 764 } 765 766 static int 767 priqcmd_delete_filter(ap) 768 struct priq_delete_filter *ap; 769 { 770 struct priq_if *pif; 771 772 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL) 773 return (EBADF); 774 775 return acc_delete_filter(&pif->pif_classifier, 776 ap->filter_handle); 777 } 778 779 static int 780 priqcmd_class_stats(ap) 781 struct priq_class_stats *ap; 782 { 783 struct priq_if *pif; 784 struct priq_class *cl; 785 struct class_stats stats, *usp; 786 int pri, error; 787 788 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL) 789 return (EBADF); 790 791 ap->maxpri = pif->pif_maxpri; 792 793 /* then, read the next N classes in the tree */ 794 usp = ap->stats; 795 for (pri = 0; pri <= pif->pif_maxpri; pri++) { 796 cl = pif->pif_classes[pri]; 797 if (cl != NULL) 798 get_class_stats(&stats, cl); 799 else 800 bzero(&stats, sizeof(stats)); 801 if ((error = copyout((caddr_t)&stats, (caddr_t)usp++, 802 sizeof(stats))) != 0) 803 return (error); 804 } 805 return (0); 806 } 807 808 static void get_class_stats(sp, cl) 809 struct class_stats *sp; 810 struct priq_class *cl; 811 { 812 sp->class_handle = clp_to_clh(cl); 813 814 sp->qlength = qlen(cl->cl_q); 815 sp->period = cl->cl_period; 816 sp->xmitcnt = cl->cl_xmitcnt; 817 sp->dropcnt = cl->cl_dropcnt; 818 819 sp->qtype = qtype(cl->cl_q); 820 #ifdef ALTQ_RED 821 if (q_is_red(cl->cl_q)) 822 red_getstats(cl->cl_red, &sp->red[0]); 823 #endif 824 #ifdef ALTQ_RIO 825 if (q_is_rio(cl->cl_q)) 826 rio_getstats((rio_t *)cl->cl_red, &sp->red[0]); 827 #endif 828 829 } 830 831 /* convert a class handle to the corresponding class pointer */ 832 static struct priq_class * 833 clh_to_clp(pif, chandle) 834 struct priq_if *pif; 835 u_long chandle; 836 { 837 struct priq_class *cl; 838 839 cl = (struct priq_class *)chandle; 840 if (chandle != ALIGN(cl)) { 841 #if 1 842 printf("clh_to_cl: unaligned pointer %p\n", cl); 843 #endif 844 return (NULL); 845 } 846 847 if (cl == NULL || cl->cl_handle != chandle || cl->cl_pif != pif) 848 return (NULL); 849 return (cl); 850 } 851 852 /* convert a class pointer to the corresponding class handle */ 853 static u_long 854 clp_to_clh(cl) 855 struct priq_class *cl; 856 { 857 return (cl->cl_handle); 858 } 859 860 #ifdef KLD_MODULE 861 862 static struct altqsw priq_sw = 863 {"priq", priqopen, priqclose, priqioctl}; 864 865 ALTQ_MODULE(altq_priq, ALTQT_PRIQ, &priq_sw); 866 867 #endif /* KLD_MODULE */ 868 869 #endif /* ALTQ_PRIQ */ 870