altq_hfsc.c revision 298133
1/* $FreeBSD: stable/10/sys/contrib/altq/altq/altq_hfsc.c 298133 2016-04-16 22:02:32Z loos $ */ 2/* $KAME: altq_hfsc.c,v 1.24 2003/12/05 05:40:46 kjc Exp $ */ 3 4/* 5 * Copyright (c) 1997-1999 Carnegie Mellon University. All Rights Reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software and 8 * its documentation is hereby granted (including for commercial or 9 * for-profit use), provided that both the copyright notice and this 10 * permission notice appear in all copies of the software, derivative 11 * works, or modified versions, and any portions thereof. 12 * 13 * THIS SOFTWARE IS EXPERIMENTAL AND IS KNOWN TO HAVE BUGS, SOME OF 14 * WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON PROVIDES THIS 15 * SOFTWARE IN ITS ``AS IS'' CONDITION, AND ANY EXPRESS OR IMPLIED 16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 21 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 22 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 25 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 * DAMAGE. 27 * 28 * Carnegie Mellon encourages (but does not require) users of this 29 * software to return any improvements or extensions that they make, 30 * and to grant Carnegie Mellon the rights to redistribute these 31 * changes without encumbrance. 32 */ 33/* 34 * H-FSC is described in Proceedings of SIGCOMM'97, 35 * "A Hierarchical Fair Service Curve Algorithm for Link-Sharing, 36 * Real-Time and Priority Service" 37 * by Ion Stoica, Hui Zhang, and T. S. Eugene Ng. 38 * 39 * Oleg Cherevko <olwi@aq.ml.com.ua> added the upperlimit for link-sharing. 40 * when a class has an upperlimit, the fit-time is computed from the 41 * upperlimit service curve. the link-sharing scheduler does not schedule 42 * a class whose fit-time exceeds the current time. 43 */ 44 45#if defined(__FreeBSD__) || defined(__NetBSD__) 46#include "opt_altq.h" 47#include "opt_inet.h" 48#ifdef __FreeBSD__ 49#include "opt_inet6.h" 50#endif 51#endif /* __FreeBSD__ || __NetBSD__ */ 52 53#ifdef ALTQ_HFSC /* hfsc is enabled by ALTQ_HFSC option in opt_altq.h */ 54 55#include <sys/param.h> 56#include <sys/malloc.h> 57#include <sys/mbuf.h> 58#include <sys/socket.h> 59#include <sys/systm.h> 60#include <sys/errno.h> 61#include <sys/queue.h> 62#if 1 /* ALTQ3_COMPAT */ 63#include <sys/sockio.h> 64#include <sys/proc.h> 65#include <sys/kernel.h> 66#endif /* ALTQ3_COMPAT */ 67 68#include <net/if.h> 69#include <net/if_var.h> 70#include <netinet/in.h> 71 72#include <netpfil/pf/pf.h> 73#include <netpfil/pf/pf_altq.h> 74#include <netpfil/pf/pf_mtag.h> 75#include <altq/altq.h> 76#include <altq/altq_hfsc.h> 77#ifdef ALTQ3_COMPAT 78#include <altq/altq_conf.h> 79#endif 80 81/* 82 * function prototypes 83 */ 84static int hfsc_clear_interface(struct hfsc_if *); 85static int hfsc_request(struct ifaltq *, int, void *); 86static void hfsc_purge(struct hfsc_if *); 87static struct hfsc_class *hfsc_class_create(struct hfsc_if *, 88 struct service_curve *, struct service_curve *, struct service_curve *, 89 struct hfsc_class *, int, int, int); 90static int hfsc_class_destroy(struct hfsc_class *); 91static struct hfsc_class *hfsc_nextclass(struct hfsc_class *); 92static int hfsc_enqueue(struct ifaltq *, struct mbuf *, 93 struct altq_pktattr *); 94static struct mbuf *hfsc_dequeue(struct ifaltq *, int); 95 96static int hfsc_addq(struct hfsc_class *, struct mbuf *); 97static struct mbuf *hfsc_getq(struct hfsc_class *); 98static struct mbuf *hfsc_pollq(struct hfsc_class *); 99static void hfsc_purgeq(struct hfsc_class *); 100 101static void update_cfmin(struct hfsc_class *); 102static void set_active(struct hfsc_class *, int); 103static void set_passive(struct hfsc_class *); 104 105static void init_ed(struct hfsc_class *, int); 106static void update_ed(struct hfsc_class *, int); 107static void update_d(struct hfsc_class *, int); 108static void init_vf(struct hfsc_class *, int); 109static void update_vf(struct hfsc_class *, int, u_int64_t); 110static void ellist_insert(struct hfsc_class *); 111static void ellist_remove(struct hfsc_class *); 112static void ellist_update(struct hfsc_class *); 113struct hfsc_class *hfsc_get_mindl(struct hfsc_if *, u_int64_t); 114static void actlist_insert(struct hfsc_class *); 115static void actlist_remove(struct hfsc_class *); 116static void actlist_update(struct hfsc_class *); 117 118static struct hfsc_class *actlist_firstfit(struct hfsc_class *, 119 u_int64_t); 120 121static __inline u_int64_t seg_x2y(u_int64_t, u_int64_t); 122static __inline u_int64_t seg_y2x(u_int64_t, u_int64_t); 123static __inline u_int64_t m2sm(u_int); 124static __inline u_int64_t m2ism(u_int); 125static __inline u_int64_t d2dx(u_int); 126static u_int sm2m(u_int64_t); 127static u_int dx2d(u_int64_t); 128 129static void sc2isc(struct service_curve *, struct internal_sc *); 130static void rtsc_init(struct runtime_sc *, struct internal_sc *, 131 u_int64_t, u_int64_t); 132static u_int64_t rtsc_y2x(struct runtime_sc *, u_int64_t); 133static u_int64_t rtsc_x2y(struct runtime_sc *, u_int64_t); 134static void rtsc_min(struct runtime_sc *, struct internal_sc *, 135 u_int64_t, u_int64_t); 136 137static void get_class_stats(struct hfsc_classstats *, 138 struct hfsc_class *); 139static struct hfsc_class *clh_to_clp(struct hfsc_if *, u_int32_t); 140 141 142#ifdef ALTQ3_COMPAT 143static struct hfsc_if *hfsc_attach(struct ifaltq *, u_int); 144static int hfsc_detach(struct hfsc_if *); 145static int hfsc_class_modify(struct hfsc_class *, struct service_curve *, 146 struct service_curve *, struct service_curve *); 147 148static int hfsccmd_if_attach(struct hfsc_attach *); 149static int hfsccmd_if_detach(struct hfsc_interface *); 150static int hfsccmd_add_class(struct hfsc_add_class *); 151static int hfsccmd_delete_class(struct hfsc_delete_class *); 152static int hfsccmd_modify_class(struct hfsc_modify_class *); 153static int hfsccmd_add_filter(struct hfsc_add_filter *); 154static int hfsccmd_delete_filter(struct hfsc_delete_filter *); 155static int hfsccmd_class_stats(struct hfsc_class_stats *); 156 157altqdev_decl(hfsc); 158#endif /* ALTQ3_COMPAT */ 159 160/* 161 * macros 162 */ 163#define is_a_parent_class(cl) ((cl)->cl_children != NULL) 164 165#define HT_INFINITY 0xffffffffffffffffLL /* infinite time value */ 166 167#ifdef ALTQ3_COMPAT 168/* hif_list keeps all hfsc_if's allocated. */ 169static struct hfsc_if *hif_list = NULL; 170#endif /* ALTQ3_COMPAT */ 171 172int 173hfsc_pfattach(struct pf_altq *a) 174{ 175 struct ifnet *ifp; 176 int s, error; 177 178 if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL) 179 return (EINVAL); 180#ifdef __NetBSD__ 181 s = splnet(); 182#else 183 s = splimp(); 184#endif 185 error = altq_attach(&ifp->if_snd, ALTQT_HFSC, a->altq_disc, 186 hfsc_enqueue, hfsc_dequeue, hfsc_request, NULL, NULL); 187 splx(s); 188 return (error); 189} 190 191int 192hfsc_add_altq(struct pf_altq *a) 193{ 194 struct hfsc_if *hif; 195 struct ifnet *ifp; 196 197 if ((ifp = ifunit(a->ifname)) == NULL) 198 return (EINVAL); 199 if (!ALTQ_IS_READY(&ifp->if_snd)) 200 return (ENODEV); 201 202 hif = malloc(sizeof(struct hfsc_if), M_DEVBUF, M_NOWAIT | M_ZERO); 203 if (hif == NULL) 204 return (ENOMEM); 205 206 TAILQ_INIT(&hif->hif_eligible); 207 hif->hif_ifq = &ifp->if_snd; 208 209 /* keep the state in pf_altq */ 210 a->altq_disc = hif; 211 212 return (0); 213} 214 215int 216hfsc_remove_altq(struct pf_altq *a) 217{ 218 struct hfsc_if *hif; 219 220 if ((hif = a->altq_disc) == NULL) 221 return (EINVAL); 222 a->altq_disc = NULL; 223 224 (void)hfsc_clear_interface(hif); 225 (void)hfsc_class_destroy(hif->hif_rootclass); 226 227 free(hif, M_DEVBUF); 228 229 return (0); 230} 231 232int 233hfsc_add_queue(struct pf_altq *a) 234{ 235 struct hfsc_if *hif; 236 struct hfsc_class *cl, *parent; 237 struct hfsc_opts *opts; 238 struct service_curve rtsc, lssc, ulsc; 239 240 if ((hif = a->altq_disc) == NULL) 241 return (EINVAL); 242 243 opts = &a->pq_u.hfsc_opts; 244 245 if (a->parent_qid == HFSC_NULLCLASS_HANDLE && 246 hif->hif_rootclass == NULL) 247 parent = NULL; 248 else if ((parent = clh_to_clp(hif, a->parent_qid)) == NULL) 249 return (EINVAL); 250 251 if (a->qid == 0) 252 return (EINVAL); 253 254 if (clh_to_clp(hif, a->qid) != NULL) 255 return (EBUSY); 256 257 rtsc.m1 = opts->rtsc_m1; 258 rtsc.d = opts->rtsc_d; 259 rtsc.m2 = opts->rtsc_m2; 260 lssc.m1 = opts->lssc_m1; 261 lssc.d = opts->lssc_d; 262 lssc.m2 = opts->lssc_m2; 263 ulsc.m1 = opts->ulsc_m1; 264 ulsc.d = opts->ulsc_d; 265 ulsc.m2 = opts->ulsc_m2; 266 267 cl = hfsc_class_create(hif, &rtsc, &lssc, &ulsc, 268 parent, a->qlimit, opts->flags, a->qid); 269 if (cl == NULL) 270 return (ENOMEM); 271 272 return (0); 273} 274 275int 276hfsc_remove_queue(struct pf_altq *a) 277{ 278 struct hfsc_if *hif; 279 struct hfsc_class *cl; 280 281 if ((hif = a->altq_disc) == NULL) 282 return (EINVAL); 283 284 if ((cl = clh_to_clp(hif, a->qid)) == NULL) 285 return (EINVAL); 286 287 return (hfsc_class_destroy(cl)); 288} 289 290int 291hfsc_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) 292{ 293 struct hfsc_if *hif; 294 struct hfsc_class *cl; 295 struct hfsc_classstats stats; 296 int error = 0; 297 298 if ((hif = altq_lookup(a->ifname, ALTQT_HFSC)) == NULL) 299 return (EBADF); 300 301 if ((cl = clh_to_clp(hif, a->qid)) == NULL) 302 return (EINVAL); 303 304 if (*nbytes < sizeof(stats)) 305 return (EINVAL); 306 307 get_class_stats(&stats, cl); 308 309 if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0) 310 return (error); 311 *nbytes = sizeof(stats); 312 return (0); 313} 314 315/* 316 * bring the interface back to the initial state by discarding 317 * all the filters and classes except the root class. 318 */ 319static int 320hfsc_clear_interface(struct hfsc_if *hif) 321{ 322 struct hfsc_class *cl; 323 324#ifdef ALTQ3_COMPAT 325 /* free the filters for this interface */ 326 acc_discard_filters(&hif->hif_classifier, NULL, 1); 327#endif 328 329 /* clear out the classes */ 330 while (hif->hif_rootclass != NULL && 331 (cl = hif->hif_rootclass->cl_children) != NULL) { 332 /* 333 * remove the first leaf class found in the hierarchy 334 * then start over 335 */ 336 for (; cl != NULL; cl = hfsc_nextclass(cl)) { 337 if (!is_a_parent_class(cl)) { 338 (void)hfsc_class_destroy(cl); 339 break; 340 } 341 } 342 } 343 344 return (0); 345} 346 347static int 348hfsc_request(struct ifaltq *ifq, int req, void *arg) 349{ 350 struct hfsc_if *hif = (struct hfsc_if *)ifq->altq_disc; 351 352 IFQ_LOCK_ASSERT(ifq); 353 354 switch (req) { 355 case ALTRQ_PURGE: 356 hfsc_purge(hif); 357 break; 358 } 359 return (0); 360} 361 362/* discard all the queued packets on the interface */ 363static void 364hfsc_purge(struct hfsc_if *hif) 365{ 366 struct hfsc_class *cl; 367 368 for (cl = hif->hif_rootclass; cl != NULL; cl = hfsc_nextclass(cl)) 369 if (!qempty(cl->cl_q)) 370 hfsc_purgeq(cl); 371 if (ALTQ_IS_ENABLED(hif->hif_ifq)) 372 hif->hif_ifq->ifq_len = 0; 373} 374 375struct hfsc_class * 376hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc, 377 struct service_curve *fsc, struct service_curve *usc, 378 struct hfsc_class *parent, int qlimit, int flags, int qid) 379{ 380 struct hfsc_class *cl, *p; 381 int i, s; 382 383 if (hif->hif_classes >= HFSC_MAX_CLASSES) 384 return (NULL); 385 386#ifndef ALTQ_RED 387 if (flags & HFCF_RED) { 388#ifdef ALTQ_DEBUG 389 printf("hfsc_class_create: RED not configured for HFSC!\n"); 390#endif 391 return (NULL); 392 } 393#endif 394#ifndef ALTQ_CODEL 395 if (flags & HFCF_CODEL) { 396#ifdef ALTQ_DEBUG 397 printf("hfsc_class_create: CODEL not configured for HFSC!\n"); 398#endif 399 return (NULL); 400 } 401#endif 402 403 cl = malloc(sizeof(struct hfsc_class), M_DEVBUF, M_NOWAIT | M_ZERO); 404 if (cl == NULL) 405 return (NULL); 406 407 cl->cl_q = malloc(sizeof(class_queue_t), M_DEVBUF, M_NOWAIT | M_ZERO); 408 if (cl->cl_q == NULL) 409 goto err_ret; 410 411 TAILQ_INIT(&cl->cl_actc); 412 413 if (qlimit == 0) 414 qlimit = 50; /* use default */ 415 qlimit(cl->cl_q) = qlimit; 416 qtype(cl->cl_q) = Q_DROPTAIL; 417 qlen(cl->cl_q) = 0; 418 qsize(cl->cl_q) = 0; 419 cl->cl_flags = flags; 420#ifdef ALTQ_RED 421 if (flags & (HFCF_RED|HFCF_RIO)) { 422 int red_flags, red_pkttime; 423 u_int m2; 424 425 m2 = 0; 426 if (rsc != NULL && rsc->m2 > m2) 427 m2 = rsc->m2; 428 if (fsc != NULL && fsc->m2 > m2) 429 m2 = fsc->m2; 430 if (usc != NULL && usc->m2 > m2) 431 m2 = usc->m2; 432 433 red_flags = 0; 434 if (flags & HFCF_ECN) 435 red_flags |= REDF_ECN; 436#ifdef ALTQ_RIO 437 if (flags & HFCF_CLEARDSCP) 438 red_flags |= RIOF_CLEARDSCP; 439#endif 440 if (m2 < 8) 441 red_pkttime = 1000 * 1000 * 1000; /* 1 sec */ 442 else 443 red_pkttime = (int64_t)hif->hif_ifq->altq_ifp->if_mtu 444 * 1000 * 1000 * 1000 / (m2 / 8); 445 if (flags & HFCF_RED) { 446 cl->cl_red = red_alloc(0, 0, 447 qlimit(cl->cl_q) * 10/100, 448 qlimit(cl->cl_q) * 30/100, 449 red_flags, red_pkttime); 450 if (cl->cl_red != NULL) 451 qtype(cl->cl_q) = Q_RED; 452 } 453#ifdef ALTQ_RIO 454 else { 455 cl->cl_red = (red_t *)rio_alloc(0, NULL, 456 red_flags, red_pkttime); 457 if (cl->cl_red != NULL) 458 qtype(cl->cl_q) = Q_RIO; 459 } 460#endif 461 } 462#endif /* ALTQ_RED */ 463#ifdef ALTQ_CODEL 464 if (flags & HFCF_CODEL) { 465 cl->cl_codel = codel_alloc(5, 100, 0); 466 if (cl->cl_codel != NULL) 467 qtype(cl->cl_q) = Q_CODEL; 468 } 469#endif 470 471 if (rsc != NULL && (rsc->m1 != 0 || rsc->m2 != 0)) { 472 cl->cl_rsc = malloc(sizeof(struct internal_sc), 473 M_DEVBUF, M_NOWAIT); 474 if (cl->cl_rsc == NULL) 475 goto err_ret; 476 sc2isc(rsc, cl->cl_rsc); 477 rtsc_init(&cl->cl_deadline, cl->cl_rsc, 0, 0); 478 rtsc_init(&cl->cl_eligible, cl->cl_rsc, 0, 0); 479 } 480 if (fsc != NULL && (fsc->m1 != 0 || fsc->m2 != 0)) { 481 cl->cl_fsc = malloc(sizeof(struct internal_sc), 482 M_DEVBUF, M_NOWAIT); 483 if (cl->cl_fsc == NULL) 484 goto err_ret; 485 sc2isc(fsc, cl->cl_fsc); 486 rtsc_init(&cl->cl_virtual, cl->cl_fsc, 0, 0); 487 } 488 if (usc != NULL && (usc->m1 != 0 || usc->m2 != 0)) { 489 cl->cl_usc = malloc(sizeof(struct internal_sc), 490 M_DEVBUF, M_NOWAIT); 491 if (cl->cl_usc == NULL) 492 goto err_ret; 493 sc2isc(usc, cl->cl_usc); 494 rtsc_init(&cl->cl_ulimit, cl->cl_usc, 0, 0); 495 } 496 497 cl->cl_id = hif->hif_classid++; 498 cl->cl_handle = qid; 499 cl->cl_hif = hif; 500 cl->cl_parent = parent; 501 502#ifdef __NetBSD__ 503 s = splnet(); 504#else 505 s = splimp(); 506#endif 507 IFQ_LOCK(hif->hif_ifq); 508 hif->hif_classes++; 509 510 /* 511 * find a free slot in the class table. if the slot matching 512 * the lower bits of qid is free, use this slot. otherwise, 513 * use the first free slot. 514 */ 515 i = qid % HFSC_MAX_CLASSES; 516 if (hif->hif_class_tbl[i] == NULL) 517 hif->hif_class_tbl[i] = cl; 518 else { 519 for (i = 0; i < HFSC_MAX_CLASSES; i++) 520 if (hif->hif_class_tbl[i] == NULL) { 521 hif->hif_class_tbl[i] = cl; 522 break; 523 } 524 if (i == HFSC_MAX_CLASSES) { 525 IFQ_UNLOCK(hif->hif_ifq); 526 splx(s); 527 goto err_ret; 528 } 529 } 530 531 if (flags & HFCF_DEFAULTCLASS) 532 hif->hif_defaultclass = cl; 533 534 if (parent == NULL) { 535 /* this is root class */ 536 hif->hif_rootclass = cl; 537 } else { 538 /* add this class to the children list of the parent */ 539 if ((p = parent->cl_children) == NULL) 540 parent->cl_children = cl; 541 else { 542 while (p->cl_siblings != NULL) 543 p = p->cl_siblings; 544 p->cl_siblings = cl; 545 } 546 } 547 IFQ_UNLOCK(hif->hif_ifq); 548 splx(s); 549 550 return (cl); 551 552 err_ret: 553 if (cl->cl_red != NULL) { 554#ifdef ALTQ_RIO 555 if (q_is_rio(cl->cl_q)) 556 rio_destroy((rio_t *)cl->cl_red); 557#endif 558#ifdef ALTQ_RED 559 if (q_is_red(cl->cl_q)) 560 red_destroy(cl->cl_red); 561#endif 562#ifdef ALTQ_CODEL 563 if (q_is_codel(cl->cl_q)) 564 codel_destroy(cl->cl_codel); 565#endif 566 } 567 if (cl->cl_fsc != NULL) 568 free(cl->cl_fsc, M_DEVBUF); 569 if (cl->cl_rsc != NULL) 570 free(cl->cl_rsc, M_DEVBUF); 571 if (cl->cl_usc != NULL) 572 free(cl->cl_usc, M_DEVBUF); 573 if (cl->cl_q != NULL) 574 free(cl->cl_q, M_DEVBUF); 575 free(cl, M_DEVBUF); 576 return (NULL); 577} 578 579static int 580hfsc_class_destroy(struct hfsc_class *cl) 581{ 582 int i, s; 583 584 if (cl == NULL) 585 return (0); 586 587 if (is_a_parent_class(cl)) 588 return (EBUSY); 589 590#ifdef __NetBSD__ 591 s = splnet(); 592#else 593 s = splimp(); 594#endif 595 IFQ_LOCK(cl->cl_hif->hif_ifq); 596 597#ifdef ALTQ3_COMPAT 598 /* delete filters referencing to this class */ 599 acc_discard_filters(&cl->cl_hif->hif_classifier, cl, 0); 600#endif /* ALTQ3_COMPAT */ 601 602 if (!qempty(cl->cl_q)) 603 hfsc_purgeq(cl); 604 605 if (cl->cl_parent == NULL) { 606 /* this is root class */ 607 } else { 608 struct hfsc_class *p = cl->cl_parent->cl_children; 609 610 if (p == cl) 611 cl->cl_parent->cl_children = cl->cl_siblings; 612 else do { 613 if (p->cl_siblings == cl) { 614 p->cl_siblings = cl->cl_siblings; 615 break; 616 } 617 } while ((p = p->cl_siblings) != NULL); 618 ASSERT(p != NULL); 619 } 620 621 for (i = 0; i < HFSC_MAX_CLASSES; i++) 622 if (cl->cl_hif->hif_class_tbl[i] == cl) { 623 cl->cl_hif->hif_class_tbl[i] = NULL; 624 break; 625 } 626 627 cl->cl_hif->hif_classes--; 628 IFQ_UNLOCK(cl->cl_hif->hif_ifq); 629 splx(s); 630 631 if (cl->cl_red != NULL) { 632#ifdef ALTQ_RIO 633 if (q_is_rio(cl->cl_q)) 634 rio_destroy((rio_t *)cl->cl_red); 635#endif 636#ifdef ALTQ_RED 637 if (q_is_red(cl->cl_q)) 638 red_destroy(cl->cl_red); 639#endif 640#ifdef ALTQ_CODEL 641 if (q_is_codel(cl->cl_q)) 642 codel_destroy(cl->cl_codel); 643#endif 644 } 645 646 IFQ_LOCK(cl->cl_hif->hif_ifq); 647 if (cl == cl->cl_hif->hif_rootclass) 648 cl->cl_hif->hif_rootclass = NULL; 649 if (cl == cl->cl_hif->hif_defaultclass) 650 cl->cl_hif->hif_defaultclass = NULL; 651 IFQ_UNLOCK(cl->cl_hif->hif_ifq); 652 653 if (cl->cl_usc != NULL) 654 free(cl->cl_usc, M_DEVBUF); 655 if (cl->cl_fsc != NULL) 656 free(cl->cl_fsc, M_DEVBUF); 657 if (cl->cl_rsc != NULL) 658 free(cl->cl_rsc, M_DEVBUF); 659 free(cl->cl_q, M_DEVBUF); 660 free(cl, M_DEVBUF); 661 662 return (0); 663} 664 665/* 666 * hfsc_nextclass returns the next class in the tree. 667 * usage: 668 * for (cl = hif->hif_rootclass; cl != NULL; cl = hfsc_nextclass(cl)) 669 * do_something; 670 */ 671static struct hfsc_class * 672hfsc_nextclass(struct hfsc_class *cl) 673{ 674 if (cl->cl_children != NULL) 675 cl = cl->cl_children; 676 else if (cl->cl_siblings != NULL) 677 cl = cl->cl_siblings; 678 else { 679 while ((cl = cl->cl_parent) != NULL) 680 if (cl->cl_siblings) { 681 cl = cl->cl_siblings; 682 break; 683 } 684 } 685 686 return (cl); 687} 688 689/* 690 * hfsc_enqueue is an enqueue function to be registered to 691 * (*altq_enqueue) in struct ifaltq. 692 */ 693static int 694hfsc_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr) 695{ 696 struct hfsc_if *hif = (struct hfsc_if *)ifq->altq_disc; 697 struct hfsc_class *cl; 698 struct pf_mtag *t; 699 int len; 700 701 IFQ_LOCK_ASSERT(ifq); 702 703 /* grab class set by classifier */ 704 if ((m->m_flags & M_PKTHDR) == 0) { 705 /* should not happen */ 706 printf("altq: packet for %s does not have pkthdr\n", 707 ifq->altq_ifp->if_xname); 708 m_freem(m); 709 return (ENOBUFS); 710 } 711 cl = NULL; 712 if ((t = pf_find_mtag(m)) != NULL) 713 cl = clh_to_clp(hif, t->qid); 714#ifdef ALTQ3_COMPAT 715 else if ((ifq->altq_flags & ALTQF_CLASSIFY) && pktattr != NULL) 716 cl = pktattr->pattr_class; 717#endif 718 if (cl == NULL || is_a_parent_class(cl)) { 719 cl = hif->hif_defaultclass; 720 if (cl == NULL) { 721 m_freem(m); 722 return (ENOBUFS); 723 } 724 } 725#ifdef ALTQ3_COMPAT 726 if (pktattr != NULL) 727 cl->cl_pktattr = pktattr; /* save proto hdr used by ECN */ 728 else 729#endif 730 cl->cl_pktattr = NULL; 731 len = m_pktlen(m); 732 if (hfsc_addq(cl, m) != 0) { 733 /* drop occurred. mbuf was freed in hfsc_addq. */ 734 PKTCNTR_ADD(&cl->cl_stats.drop_cnt, len); 735 return (ENOBUFS); 736 } 737 IFQ_INC_LEN(ifq); 738 cl->cl_hif->hif_packets++; 739 740 /* successfully queued. */ 741 if (qlen(cl->cl_q) == 1) 742 set_active(cl, m_pktlen(m)); 743 744 return (0); 745} 746 747/* 748 * hfsc_dequeue is a dequeue function to be registered to 749 * (*altq_dequeue) in struct ifaltq. 750 * 751 * note: ALTDQ_POLL returns the next packet without removing the packet 752 * from the queue. ALTDQ_REMOVE is a normal dequeue operation. 753 * ALTDQ_REMOVE must return the same packet if called immediately 754 * after ALTDQ_POLL. 755 */ 756static struct mbuf * 757hfsc_dequeue(struct ifaltq *ifq, int op) 758{ 759 struct hfsc_if *hif = (struct hfsc_if *)ifq->altq_disc; 760 struct hfsc_class *cl; 761 struct mbuf *m; 762 int len, next_len; 763 int realtime = 0; 764 u_int64_t cur_time; 765 766 IFQ_LOCK_ASSERT(ifq); 767 768 if (hif->hif_packets == 0) 769 /* no packet in the tree */ 770 return (NULL); 771 772 cur_time = read_machclk(); 773 774 if (op == ALTDQ_REMOVE && hif->hif_pollcache != NULL) { 775 776 cl = hif->hif_pollcache; 777 hif->hif_pollcache = NULL; 778 /* check if the class was scheduled by real-time criteria */ 779 if (cl->cl_rsc != NULL) 780 realtime = (cl->cl_e <= cur_time); 781 } else { 782 /* 783 * if there are eligible classes, use real-time criteria. 784 * find the class with the minimum deadline among 785 * the eligible classes. 786 */ 787 if ((cl = hfsc_get_mindl(hif, cur_time)) 788 != NULL) { 789 realtime = 1; 790 } else { 791#ifdef ALTQ_DEBUG 792 int fits = 0; 793#endif 794 /* 795 * use link-sharing criteria 796 * get the class with the minimum vt in the hierarchy 797 */ 798 cl = hif->hif_rootclass; 799 while (is_a_parent_class(cl)) { 800 801 cl = actlist_firstfit(cl, cur_time); 802 if (cl == NULL) { 803#ifdef ALTQ_DEBUG 804 if (fits > 0) 805 printf("%d fit but none found\n",fits); 806#endif 807 return (NULL); 808 } 809 /* 810 * update parent's cl_cvtmin. 811 * don't update if the new vt is smaller. 812 */ 813 if (cl->cl_parent->cl_cvtmin < cl->cl_vt) 814 cl->cl_parent->cl_cvtmin = cl->cl_vt; 815#ifdef ALTQ_DEBUG 816 fits++; 817#endif 818 } 819 } 820 821 if (op == ALTDQ_POLL) { 822 hif->hif_pollcache = cl; 823 m = hfsc_pollq(cl); 824 return (m); 825 } 826 } 827 828 m = hfsc_getq(cl); 829 if (m == NULL) 830 panic("hfsc_dequeue:"); 831 len = m_pktlen(m); 832 cl->cl_hif->hif_packets--; 833 IFQ_DEC_LEN(ifq); 834 PKTCNTR_ADD(&cl->cl_stats.xmit_cnt, len); 835 836 update_vf(cl, len, cur_time); 837 if (realtime) 838 cl->cl_cumul += len; 839 840 if (!qempty(cl->cl_q)) { 841 if (cl->cl_rsc != NULL) { 842 /* update ed */ 843 next_len = m_pktlen(qhead(cl->cl_q)); 844 845 if (realtime) 846 update_ed(cl, next_len); 847 else 848 update_d(cl, next_len); 849 } 850 } else { 851 /* the class becomes passive */ 852 set_passive(cl); 853 } 854 855 return (m); 856} 857 858static int 859hfsc_addq(struct hfsc_class *cl, struct mbuf *m) 860{ 861 862#ifdef ALTQ_RIO 863 if (q_is_rio(cl->cl_q)) 864 return rio_addq((rio_t *)cl->cl_red, cl->cl_q, 865 m, cl->cl_pktattr); 866#endif 867#ifdef ALTQ_RED 868 if (q_is_red(cl->cl_q)) 869 return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr); 870#endif 871#ifdef ALTQ_CODEL 872 if (q_is_codel(cl->cl_q)) 873 return codel_addq(cl->cl_codel, cl->cl_q, m); 874#endif 875 if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) { 876 m_freem(m); 877 return (-1); 878 } 879 880 if (cl->cl_flags & HFCF_CLEARDSCP) 881 write_dsfield(m, cl->cl_pktattr, 0); 882 883 _addq(cl->cl_q, m); 884 885 return (0); 886} 887 888static struct mbuf * 889hfsc_getq(struct hfsc_class *cl) 890{ 891#ifdef ALTQ_RIO 892 if (q_is_rio(cl->cl_q)) 893 return rio_getq((rio_t *)cl->cl_red, cl->cl_q); 894#endif 895#ifdef ALTQ_RED 896 if (q_is_red(cl->cl_q)) 897 return red_getq(cl->cl_red, cl->cl_q); 898#endif 899#ifdef ALTQ_CODEL 900 if (q_is_codel(cl->cl_q)) 901 return codel_getq(cl->cl_codel, cl->cl_q); 902#endif 903 return _getq(cl->cl_q); 904} 905 906static struct mbuf * 907hfsc_pollq(struct hfsc_class *cl) 908{ 909 return qhead(cl->cl_q); 910} 911 912static void 913hfsc_purgeq(struct hfsc_class *cl) 914{ 915 struct mbuf *m; 916 917 if (qempty(cl->cl_q)) 918 return; 919 920 while ((m = _getq(cl->cl_q)) != NULL) { 921 PKTCNTR_ADD(&cl->cl_stats.drop_cnt, m_pktlen(m)); 922 m_freem(m); 923 cl->cl_hif->hif_packets--; 924 IFQ_DEC_LEN(cl->cl_hif->hif_ifq); 925 } 926 ASSERT(qlen(cl->cl_q) == 0); 927 928 update_vf(cl, 0, 0); /* remove cl from the actlist */ 929 set_passive(cl); 930} 931 932static void 933set_active(struct hfsc_class *cl, int len) 934{ 935 if (cl->cl_rsc != NULL) 936 init_ed(cl, len); 937 if (cl->cl_fsc != NULL) 938 init_vf(cl, len); 939 940 cl->cl_stats.period++; 941} 942 943static void 944set_passive(struct hfsc_class *cl) 945{ 946 if (cl->cl_rsc != NULL) 947 ellist_remove(cl); 948 949 /* 950 * actlist is now handled in update_vf() so that update_vf(cl, 0, 0) 951 * needs to be called explicitly to remove a class from actlist 952 */ 953} 954 955static void 956init_ed(struct hfsc_class *cl, int next_len) 957{ 958 u_int64_t cur_time; 959 960 cur_time = read_machclk(); 961 962 /* update the deadline curve */ 963 rtsc_min(&cl->cl_deadline, cl->cl_rsc, cur_time, cl->cl_cumul); 964 965 /* 966 * update the eligible curve. 967 * for concave, it is equal to the deadline curve. 968 * for convex, it is a linear curve with slope m2. 969 */ 970 cl->cl_eligible = cl->cl_deadline; 971 if (cl->cl_rsc->sm1 <= cl->cl_rsc->sm2) { 972 cl->cl_eligible.dx = 0; 973 cl->cl_eligible.dy = 0; 974 } 975 976 /* compute e and d */ 977 cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul); 978 cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); 979 980 ellist_insert(cl); 981} 982 983static void 984update_ed(struct hfsc_class *cl, int next_len) 985{ 986 cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul); 987 cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); 988 989 ellist_update(cl); 990} 991 992static void 993update_d(struct hfsc_class *cl, int next_len) 994{ 995 cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); 996} 997 998static void 999init_vf(struct hfsc_class *cl, int len) 1000{ 1001 struct hfsc_class *max_cl, *p; 1002 u_int64_t vt, f, cur_time; 1003 int go_active; 1004 1005 cur_time = 0; 1006 go_active = 1; 1007 for ( ; cl->cl_parent != NULL; cl = cl->cl_parent) { 1008 1009 if (go_active && cl->cl_nactive++ == 0) 1010 go_active = 1; 1011 else 1012 go_active = 0; 1013 1014 if (go_active) { 1015 max_cl = TAILQ_LAST(&cl->cl_parent->cl_actc, acthead); 1016 if (max_cl != NULL) { 1017 /* 1018 * set vt to the average of the min and max 1019 * classes. if the parent's period didn't 1020 * change, don't decrease vt of the class. 1021 */ 1022 vt = max_cl->cl_vt; 1023 if (cl->cl_parent->cl_cvtmin != 0) 1024 vt = (cl->cl_parent->cl_cvtmin + vt)/2; 1025 1026 if (cl->cl_parent->cl_vtperiod != 1027 cl->cl_parentperiod || vt > cl->cl_vt) 1028 cl->cl_vt = vt; 1029 } else { 1030 /* 1031 * first child for a new parent backlog period. 1032 * add parent's cvtmax to vtoff of children 1033 * to make a new vt (vtoff + vt) larger than 1034 * the vt in the last period for all children. 1035 */ 1036 vt = cl->cl_parent->cl_cvtmax; 1037 for (p = cl->cl_parent->cl_children; p != NULL; 1038 p = p->cl_siblings) 1039 p->cl_vtoff += vt; 1040 cl->cl_vt = 0; 1041 cl->cl_parent->cl_cvtmax = 0; 1042 cl->cl_parent->cl_cvtmin = 0; 1043 } 1044 cl->cl_initvt = cl->cl_vt; 1045 1046 /* update the virtual curve */ 1047 vt = cl->cl_vt + cl->cl_vtoff; 1048 rtsc_min(&cl->cl_virtual, cl->cl_fsc, vt, cl->cl_total); 1049 if (cl->cl_virtual.x == vt) { 1050 cl->cl_virtual.x -= cl->cl_vtoff; 1051 cl->cl_vtoff = 0; 1052 } 1053 cl->cl_vtadj = 0; 1054 1055 cl->cl_vtperiod++; /* increment vt period */ 1056 cl->cl_parentperiod = cl->cl_parent->cl_vtperiod; 1057 if (cl->cl_parent->cl_nactive == 0) 1058 cl->cl_parentperiod++; 1059 cl->cl_f = 0; 1060 1061 actlist_insert(cl); 1062 1063 if (cl->cl_usc != NULL) { 1064 /* class has upper limit curve */ 1065 if (cur_time == 0) 1066 cur_time = read_machclk(); 1067 1068 /* update the ulimit curve */ 1069 rtsc_min(&cl->cl_ulimit, cl->cl_usc, cur_time, 1070 cl->cl_total); 1071 /* compute myf */ 1072 cl->cl_myf = rtsc_y2x(&cl->cl_ulimit, 1073 cl->cl_total); 1074 cl->cl_myfadj = 0; 1075 } 1076 } 1077 1078 if (cl->cl_myf > cl->cl_cfmin) 1079 f = cl->cl_myf; 1080 else 1081 f = cl->cl_cfmin; 1082 if (f != cl->cl_f) { 1083 cl->cl_f = f; 1084 update_cfmin(cl->cl_parent); 1085 } 1086 } 1087} 1088 1089static void 1090update_vf(struct hfsc_class *cl, int len, u_int64_t cur_time) 1091{ 1092 u_int64_t f, myf_bound, delta; 1093 int go_passive; 1094 1095 go_passive = qempty(cl->cl_q); 1096 1097 for (; cl->cl_parent != NULL; cl = cl->cl_parent) { 1098 1099 cl->cl_total += len; 1100 1101 if (cl->cl_fsc == NULL || cl->cl_nactive == 0) 1102 continue; 1103 1104 if (go_passive && --cl->cl_nactive == 0) 1105 go_passive = 1; 1106 else 1107 go_passive = 0; 1108 1109 if (go_passive) { 1110 /* no more active child, going passive */ 1111 1112 /* update cvtmax of the parent class */ 1113 if (cl->cl_vt > cl->cl_parent->cl_cvtmax) 1114 cl->cl_parent->cl_cvtmax = cl->cl_vt; 1115 1116 /* remove this class from the vt list */ 1117 actlist_remove(cl); 1118 1119 update_cfmin(cl->cl_parent); 1120 1121 continue; 1122 } 1123 1124 /* 1125 * update vt and f 1126 */ 1127 cl->cl_vt = rtsc_y2x(&cl->cl_virtual, cl->cl_total) 1128 - cl->cl_vtoff + cl->cl_vtadj; 1129 1130 /* 1131 * if vt of the class is smaller than cvtmin, 1132 * the class was skipped in the past due to non-fit. 1133 * if so, we need to adjust vtadj. 1134 */ 1135 if (cl->cl_vt < cl->cl_parent->cl_cvtmin) { 1136 cl->cl_vtadj += cl->cl_parent->cl_cvtmin - cl->cl_vt; 1137 cl->cl_vt = cl->cl_parent->cl_cvtmin; 1138 } 1139 1140 /* update the vt list */ 1141 actlist_update(cl); 1142 1143 if (cl->cl_usc != NULL) { 1144 cl->cl_myf = cl->cl_myfadj 1145 + rtsc_y2x(&cl->cl_ulimit, cl->cl_total); 1146 1147 /* 1148 * if myf lags behind by more than one clock tick 1149 * from the current time, adjust myfadj to prevent 1150 * a rate-limited class from going greedy. 1151 * in a steady state under rate-limiting, myf 1152 * fluctuates within one clock tick. 1153 */ 1154 myf_bound = cur_time - machclk_per_tick; 1155 if (cl->cl_myf < myf_bound) { 1156 delta = cur_time - cl->cl_myf; 1157 cl->cl_myfadj += delta; 1158 cl->cl_myf += delta; 1159 } 1160 } 1161 1162 /* cl_f is max(cl_myf, cl_cfmin) */ 1163 if (cl->cl_myf > cl->cl_cfmin) 1164 f = cl->cl_myf; 1165 else 1166 f = cl->cl_cfmin; 1167 if (f != cl->cl_f) { 1168 cl->cl_f = f; 1169 update_cfmin(cl->cl_parent); 1170 } 1171 } 1172} 1173 1174static void 1175update_cfmin(struct hfsc_class *cl) 1176{ 1177 struct hfsc_class *p; 1178 u_int64_t cfmin; 1179 1180 if (TAILQ_EMPTY(&cl->cl_actc)) { 1181 cl->cl_cfmin = 0; 1182 return; 1183 } 1184 cfmin = HT_INFINITY; 1185 TAILQ_FOREACH(p, &cl->cl_actc, cl_actlist) { 1186 if (p->cl_f == 0) { 1187 cl->cl_cfmin = 0; 1188 return; 1189 } 1190 if (p->cl_f < cfmin) 1191 cfmin = p->cl_f; 1192 } 1193 cl->cl_cfmin = cfmin; 1194} 1195 1196/* 1197 * TAILQ based ellist and actlist implementation 1198 * (ion wanted to make a calendar queue based implementation) 1199 */ 1200/* 1201 * eligible list holds backlogged classes being sorted by their eligible times. 1202 * there is one eligible list per interface. 1203 */ 1204 1205static void 1206ellist_insert(struct hfsc_class *cl) 1207{ 1208 struct hfsc_if *hif = cl->cl_hif; 1209 struct hfsc_class *p; 1210 1211 /* check the last entry first */ 1212 if ((p = TAILQ_LAST(&hif->hif_eligible, elighead)) == NULL || 1213 p->cl_e <= cl->cl_e) { 1214 TAILQ_INSERT_TAIL(&hif->hif_eligible, cl, cl_ellist); 1215 return; 1216 } 1217 1218 TAILQ_FOREACH(p, &hif->hif_eligible, cl_ellist) { 1219 if (cl->cl_e < p->cl_e) { 1220 TAILQ_INSERT_BEFORE(p, cl, cl_ellist); 1221 return; 1222 } 1223 } 1224 ASSERT(0); /* should not reach here */ 1225} 1226 1227static void 1228ellist_remove(struct hfsc_class *cl) 1229{ 1230 struct hfsc_if *hif = cl->cl_hif; 1231 1232 TAILQ_REMOVE(&hif->hif_eligible, cl, cl_ellist); 1233} 1234 1235static void 1236ellist_update(struct hfsc_class *cl) 1237{ 1238 struct hfsc_if *hif = cl->cl_hif; 1239 struct hfsc_class *p, *last; 1240 1241 /* 1242 * the eligible time of a class increases monotonically. 1243 * if the next entry has a larger eligible time, nothing to do. 1244 */ 1245 p = TAILQ_NEXT(cl, cl_ellist); 1246 if (p == NULL || cl->cl_e <= p->cl_e) 1247 return; 1248 1249 /* check the last entry */ 1250 last = TAILQ_LAST(&hif->hif_eligible, elighead); 1251 ASSERT(last != NULL); 1252 if (last->cl_e <= cl->cl_e) { 1253 TAILQ_REMOVE(&hif->hif_eligible, cl, cl_ellist); 1254 TAILQ_INSERT_TAIL(&hif->hif_eligible, cl, cl_ellist); 1255 return; 1256 } 1257 1258 /* 1259 * the new position must be between the next entry 1260 * and the last entry 1261 */ 1262 while ((p = TAILQ_NEXT(p, cl_ellist)) != NULL) { 1263 if (cl->cl_e < p->cl_e) { 1264 TAILQ_REMOVE(&hif->hif_eligible, cl, cl_ellist); 1265 TAILQ_INSERT_BEFORE(p, cl, cl_ellist); 1266 return; 1267 } 1268 } 1269 ASSERT(0); /* should not reach here */ 1270} 1271 1272/* find the class with the minimum deadline among the eligible classes */ 1273struct hfsc_class * 1274hfsc_get_mindl(struct hfsc_if *hif, u_int64_t cur_time) 1275{ 1276 struct hfsc_class *p, *cl = NULL; 1277 1278 TAILQ_FOREACH(p, &hif->hif_eligible, cl_ellist) { 1279 if (p->cl_e > cur_time) 1280 break; 1281 if (cl == NULL || p->cl_d < cl->cl_d) 1282 cl = p; 1283 } 1284 return (cl); 1285} 1286 1287/* 1288 * active children list holds backlogged child classes being sorted 1289 * by their virtual time. 1290 * each intermediate class has one active children list. 1291 */ 1292 1293static void 1294actlist_insert(struct hfsc_class *cl) 1295{ 1296 struct hfsc_class *p; 1297 1298 /* check the last entry first */ 1299 if ((p = TAILQ_LAST(&cl->cl_parent->cl_actc, acthead)) == NULL 1300 || p->cl_vt <= cl->cl_vt) { 1301 TAILQ_INSERT_TAIL(&cl->cl_parent->cl_actc, cl, cl_actlist); 1302 return; 1303 } 1304 1305 TAILQ_FOREACH(p, &cl->cl_parent->cl_actc, cl_actlist) { 1306 if (cl->cl_vt < p->cl_vt) { 1307 TAILQ_INSERT_BEFORE(p, cl, cl_actlist); 1308 return; 1309 } 1310 } 1311 ASSERT(0); /* should not reach here */ 1312} 1313 1314static void 1315actlist_remove(struct hfsc_class *cl) 1316{ 1317 TAILQ_REMOVE(&cl->cl_parent->cl_actc, cl, cl_actlist); 1318} 1319 1320static void 1321actlist_update(struct hfsc_class *cl) 1322{ 1323 struct hfsc_class *p, *last; 1324 1325 /* 1326 * the virtual time of a class increases monotonically during its 1327 * backlogged period. 1328 * if the next entry has a larger virtual time, nothing to do. 1329 */ 1330 p = TAILQ_NEXT(cl, cl_actlist); 1331 if (p == NULL || cl->cl_vt < p->cl_vt) 1332 return; 1333 1334 /* check the last entry */ 1335 last = TAILQ_LAST(&cl->cl_parent->cl_actc, acthead); 1336 ASSERT(last != NULL); 1337 if (last->cl_vt <= cl->cl_vt) { 1338 TAILQ_REMOVE(&cl->cl_parent->cl_actc, cl, cl_actlist); 1339 TAILQ_INSERT_TAIL(&cl->cl_parent->cl_actc, cl, cl_actlist); 1340 return; 1341 } 1342 1343 /* 1344 * the new position must be between the next entry 1345 * and the last entry 1346 */ 1347 while ((p = TAILQ_NEXT(p, cl_actlist)) != NULL) { 1348 if (cl->cl_vt < p->cl_vt) { 1349 TAILQ_REMOVE(&cl->cl_parent->cl_actc, cl, cl_actlist); 1350 TAILQ_INSERT_BEFORE(p, cl, cl_actlist); 1351 return; 1352 } 1353 } 1354 ASSERT(0); /* should not reach here */ 1355} 1356 1357static struct hfsc_class * 1358actlist_firstfit(struct hfsc_class *cl, u_int64_t cur_time) 1359{ 1360 struct hfsc_class *p; 1361 1362 TAILQ_FOREACH(p, &cl->cl_actc, cl_actlist) { 1363 if (p->cl_f <= cur_time) 1364 return (p); 1365 } 1366 return (NULL); 1367} 1368 1369/* 1370 * service curve support functions 1371 * 1372 * external service curve parameters 1373 * m: bits/sec 1374 * d: msec 1375 * internal service curve parameters 1376 * sm: (bytes/tsc_interval) << SM_SHIFT 1377 * ism: (tsc_count/byte) << ISM_SHIFT 1378 * dx: tsc_count 1379 * 1380 * SM_SHIFT and ISM_SHIFT are scaled in order to keep effective digits. 1381 * we should be able to handle 100K-1Gbps linkspeed with 200Hz-1GHz CPU 1382 * speed. SM_SHIFT and ISM_SHIFT are selected to have at least 3 effective 1383 * digits in decimal using the following table. 1384 * 1385 * bits/sec 100Kbps 1Mbps 10Mbps 100Mbps 1Gbps 1386 * ----------+------------------------------------------------------- 1387 * bytes/nsec 12.5e-6 125e-6 1250e-6 12500e-6 125000e-6 1388 * sm(500MHz) 25.0e-6 250e-6 2500e-6 25000e-6 250000e-6 1389 * sm(200MHz) 62.5e-6 625e-6 6250e-6 62500e-6 625000e-6 1390 * 1391 * nsec/byte 80000 8000 800 80 8 1392 * ism(500MHz) 40000 4000 400 40 4 1393 * ism(200MHz) 16000 1600 160 16 1.6 1394 */ 1395#define SM_SHIFT 24 1396#define ISM_SHIFT 10 1397 1398#define SM_MASK ((1LL << SM_SHIFT) - 1) 1399#define ISM_MASK ((1LL << ISM_SHIFT) - 1) 1400 1401static __inline u_int64_t 1402seg_x2y(u_int64_t x, u_int64_t sm) 1403{ 1404 u_int64_t y; 1405 1406 /* 1407 * compute 1408 * y = x * sm >> SM_SHIFT 1409 * but divide it for the upper and lower bits to avoid overflow 1410 */ 1411 y = (x >> SM_SHIFT) * sm + (((x & SM_MASK) * sm) >> SM_SHIFT); 1412 return (y); 1413} 1414 1415static __inline u_int64_t 1416seg_y2x(u_int64_t y, u_int64_t ism) 1417{ 1418 u_int64_t x; 1419 1420 if (y == 0) 1421 x = 0; 1422 else if (ism == HT_INFINITY) 1423 x = HT_INFINITY; 1424 else { 1425 x = (y >> ISM_SHIFT) * ism 1426 + (((y & ISM_MASK) * ism) >> ISM_SHIFT); 1427 } 1428 return (x); 1429} 1430 1431static __inline u_int64_t 1432m2sm(u_int m) 1433{ 1434 u_int64_t sm; 1435 1436 sm = ((u_int64_t)m << SM_SHIFT) / 8 / machclk_freq; 1437 return (sm); 1438} 1439 1440static __inline u_int64_t 1441m2ism(u_int m) 1442{ 1443 u_int64_t ism; 1444 1445 if (m == 0) 1446 ism = HT_INFINITY; 1447 else 1448 ism = ((u_int64_t)machclk_freq << ISM_SHIFT) * 8 / m; 1449 return (ism); 1450} 1451 1452static __inline u_int64_t 1453d2dx(u_int d) 1454{ 1455 u_int64_t dx; 1456 1457 dx = ((u_int64_t)d * machclk_freq) / 1000; 1458 return (dx); 1459} 1460 1461static u_int 1462sm2m(u_int64_t sm) 1463{ 1464 u_int64_t m; 1465 1466 m = (sm * 8 * machclk_freq) >> SM_SHIFT; 1467 return ((u_int)m); 1468} 1469 1470static u_int 1471dx2d(u_int64_t dx) 1472{ 1473 u_int64_t d; 1474 1475 d = dx * 1000 / machclk_freq; 1476 return ((u_int)d); 1477} 1478 1479static void 1480sc2isc(struct service_curve *sc, struct internal_sc *isc) 1481{ 1482 isc->sm1 = m2sm(sc->m1); 1483 isc->ism1 = m2ism(sc->m1); 1484 isc->dx = d2dx(sc->d); 1485 isc->dy = seg_x2y(isc->dx, isc->sm1); 1486 isc->sm2 = m2sm(sc->m2); 1487 isc->ism2 = m2ism(sc->m2); 1488} 1489 1490/* 1491 * initialize the runtime service curve with the given internal 1492 * service curve starting at (x, y). 1493 */ 1494static void 1495rtsc_init(struct runtime_sc *rtsc, struct internal_sc * isc, u_int64_t x, 1496 u_int64_t y) 1497{ 1498 rtsc->x = x; 1499 rtsc->y = y; 1500 rtsc->sm1 = isc->sm1; 1501 rtsc->ism1 = isc->ism1; 1502 rtsc->dx = isc->dx; 1503 rtsc->dy = isc->dy; 1504 rtsc->sm2 = isc->sm2; 1505 rtsc->ism2 = isc->ism2; 1506} 1507 1508/* 1509 * calculate the y-projection of the runtime service curve by the 1510 * given x-projection value 1511 */ 1512static u_int64_t 1513rtsc_y2x(struct runtime_sc *rtsc, u_int64_t y) 1514{ 1515 u_int64_t x; 1516 1517 if (y < rtsc->y) 1518 x = rtsc->x; 1519 else if (y <= rtsc->y + rtsc->dy) { 1520 /* x belongs to the 1st segment */ 1521 if (rtsc->dy == 0) 1522 x = rtsc->x + rtsc->dx; 1523 else 1524 x = rtsc->x + seg_y2x(y - rtsc->y, rtsc->ism1); 1525 } else { 1526 /* x belongs to the 2nd segment */ 1527 x = rtsc->x + rtsc->dx 1528 + seg_y2x(y - rtsc->y - rtsc->dy, rtsc->ism2); 1529 } 1530 return (x); 1531} 1532 1533static u_int64_t 1534rtsc_x2y(struct runtime_sc *rtsc, u_int64_t x) 1535{ 1536 u_int64_t y; 1537 1538 if (x <= rtsc->x) 1539 y = rtsc->y; 1540 else if (x <= rtsc->x + rtsc->dx) 1541 /* y belongs to the 1st segment */ 1542 y = rtsc->y + seg_x2y(x - rtsc->x, rtsc->sm1); 1543 else 1544 /* y belongs to the 2nd segment */ 1545 y = rtsc->y + rtsc->dy 1546 + seg_x2y(x - rtsc->x - rtsc->dx, rtsc->sm2); 1547 return (y); 1548} 1549 1550/* 1551 * update the runtime service curve by taking the minimum of the current 1552 * runtime service curve and the service curve starting at (x, y). 1553 */ 1554static void 1555rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u_int64_t x, 1556 u_int64_t y) 1557{ 1558 u_int64_t y1, y2, dx, dy; 1559 1560 if (isc->sm1 <= isc->sm2) { 1561 /* service curve is convex */ 1562 y1 = rtsc_x2y(rtsc, x); 1563 if (y1 < y) 1564 /* the current rtsc is smaller */ 1565 return; 1566 rtsc->x = x; 1567 rtsc->y = y; 1568 return; 1569 } 1570 1571 /* 1572 * service curve is concave 1573 * compute the two y values of the current rtsc 1574 * y1: at x 1575 * y2: at (x + dx) 1576 */ 1577 y1 = rtsc_x2y(rtsc, x); 1578 if (y1 <= y) { 1579 /* rtsc is below isc, no change to rtsc */ 1580 return; 1581 } 1582 1583 y2 = rtsc_x2y(rtsc, x + isc->dx); 1584 if (y2 >= y + isc->dy) { 1585 /* rtsc is above isc, replace rtsc by isc */ 1586 rtsc->x = x; 1587 rtsc->y = y; 1588 rtsc->dx = isc->dx; 1589 rtsc->dy = isc->dy; 1590 return; 1591 } 1592 1593 /* 1594 * the two curves intersect 1595 * compute the offsets (dx, dy) using the reverse 1596 * function of seg_x2y() 1597 * seg_x2y(dx, sm1) == seg_x2y(dx, sm2) + (y1 - y) 1598 */ 1599 dx = ((y1 - y) << SM_SHIFT) / (isc->sm1 - isc->sm2); 1600 /* 1601 * check if (x, y1) belongs to the 1st segment of rtsc. 1602 * if so, add the offset. 1603 */ 1604 if (rtsc->x + rtsc->dx > x) 1605 dx += rtsc->x + rtsc->dx - x; 1606 dy = seg_x2y(dx, isc->sm1); 1607 1608 rtsc->x = x; 1609 rtsc->y = y; 1610 rtsc->dx = dx; 1611 rtsc->dy = dy; 1612 return; 1613} 1614 1615static void 1616get_class_stats(struct hfsc_classstats *sp, struct hfsc_class *cl) 1617{ 1618 sp->class_id = cl->cl_id; 1619 sp->class_handle = cl->cl_handle; 1620 1621 if (cl->cl_rsc != NULL) { 1622 sp->rsc.m1 = sm2m(cl->cl_rsc->sm1); 1623 sp->rsc.d = dx2d(cl->cl_rsc->dx); 1624 sp->rsc.m2 = sm2m(cl->cl_rsc->sm2); 1625 } else { 1626 sp->rsc.m1 = 0; 1627 sp->rsc.d = 0; 1628 sp->rsc.m2 = 0; 1629 } 1630 if (cl->cl_fsc != NULL) { 1631 sp->fsc.m1 = sm2m(cl->cl_fsc->sm1); 1632 sp->fsc.d = dx2d(cl->cl_fsc->dx); 1633 sp->fsc.m2 = sm2m(cl->cl_fsc->sm2); 1634 } else { 1635 sp->fsc.m1 = 0; 1636 sp->fsc.d = 0; 1637 sp->fsc.m2 = 0; 1638 } 1639 if (cl->cl_usc != NULL) { 1640 sp->usc.m1 = sm2m(cl->cl_usc->sm1); 1641 sp->usc.d = dx2d(cl->cl_usc->dx); 1642 sp->usc.m2 = sm2m(cl->cl_usc->sm2); 1643 } else { 1644 sp->usc.m1 = 0; 1645 sp->usc.d = 0; 1646 sp->usc.m2 = 0; 1647 } 1648 1649 sp->total = cl->cl_total; 1650 sp->cumul = cl->cl_cumul; 1651 1652 sp->d = cl->cl_d; 1653 sp->e = cl->cl_e; 1654 sp->vt = cl->cl_vt; 1655 sp->f = cl->cl_f; 1656 1657 sp->initvt = cl->cl_initvt; 1658 sp->vtperiod = cl->cl_vtperiod; 1659 sp->parentperiod = cl->cl_parentperiod; 1660 sp->nactive = cl->cl_nactive; 1661 sp->vtoff = cl->cl_vtoff; 1662 sp->cvtmax = cl->cl_cvtmax; 1663 sp->myf = cl->cl_myf; 1664 sp->cfmin = cl->cl_cfmin; 1665 sp->cvtmin = cl->cl_cvtmin; 1666 sp->myfadj = cl->cl_myfadj; 1667 sp->vtadj = cl->cl_vtadj; 1668 1669 sp->cur_time = read_machclk(); 1670 sp->machclk_freq = machclk_freq; 1671 1672 sp->qlength = qlen(cl->cl_q); 1673 sp->qlimit = qlimit(cl->cl_q); 1674 sp->xmit_cnt = cl->cl_stats.xmit_cnt; 1675 sp->drop_cnt = cl->cl_stats.drop_cnt; 1676 sp->period = cl->cl_stats.period; 1677 1678 sp->qtype = qtype(cl->cl_q); 1679#ifdef ALTQ_RED 1680 if (q_is_red(cl->cl_q)) 1681 red_getstats(cl->cl_red, &sp->red[0]); 1682#endif 1683#ifdef ALTQ_RIO 1684 if (q_is_rio(cl->cl_q)) 1685 rio_getstats((rio_t *)cl->cl_red, &sp->red[0]); 1686#endif 1687#ifdef ALTQ_CODEL 1688 if (q_is_codel(cl->cl_q)) 1689 codel_getstats(cl->cl_codel, &sp->codel); 1690#endif 1691} 1692 1693/* convert a class handle to the corresponding class pointer */ 1694static struct hfsc_class * 1695clh_to_clp(struct hfsc_if *hif, u_int32_t chandle) 1696{ 1697 int i; 1698 struct hfsc_class *cl; 1699 1700 if (chandle == 0) 1701 return (NULL); 1702 /* 1703 * first, try optimistically the slot matching the lower bits of 1704 * the handle. if it fails, do the linear table search. 1705 */ 1706 i = chandle % HFSC_MAX_CLASSES; 1707 if ((cl = hif->hif_class_tbl[i]) != NULL && cl->cl_handle == chandle) 1708 return (cl); 1709 for (i = 0; i < HFSC_MAX_CLASSES; i++) 1710 if ((cl = hif->hif_class_tbl[i]) != NULL && 1711 cl->cl_handle == chandle) 1712 return (cl); 1713 return (NULL); 1714} 1715 1716#ifdef ALTQ3_COMPAT 1717static struct hfsc_if * 1718hfsc_attach(ifq, bandwidth) 1719 struct ifaltq *ifq; 1720 u_int bandwidth; 1721{ 1722 struct hfsc_if *hif; 1723 1724 hif = malloc(sizeof(struct hfsc_if), M_DEVBUF, M_WAITOK); 1725 if (hif == NULL) 1726 return (NULL); 1727 bzero(hif, sizeof(struct hfsc_if)); 1728 1729 hif->hif_eligible = ellist_alloc(); 1730 if (hif->hif_eligible == NULL) { 1731 free(hif, M_DEVBUF); 1732 return NULL; 1733 } 1734 1735 hif->hif_ifq = ifq; 1736 1737 /* add this state to the hfsc list */ 1738 hif->hif_next = hif_list; 1739 hif_list = hif; 1740 1741 return (hif); 1742} 1743 1744static int 1745hfsc_detach(hif) 1746 struct hfsc_if *hif; 1747{ 1748 (void)hfsc_clear_interface(hif); 1749 (void)hfsc_class_destroy(hif->hif_rootclass); 1750 1751 /* remove this interface from the hif list */ 1752 if (hif_list == hif) 1753 hif_list = hif->hif_next; 1754 else { 1755 struct hfsc_if *h; 1756 1757 for (h = hif_list; h != NULL; h = h->hif_next) 1758 if (h->hif_next == hif) { 1759 h->hif_next = hif->hif_next; 1760 break; 1761 } 1762 ASSERT(h != NULL); 1763 } 1764 1765 ellist_destroy(hif->hif_eligible); 1766 1767 free(hif, M_DEVBUF); 1768 1769 return (0); 1770} 1771 1772static int 1773hfsc_class_modify(cl, rsc, fsc, usc) 1774 struct hfsc_class *cl; 1775 struct service_curve *rsc, *fsc, *usc; 1776{ 1777 struct internal_sc *rsc_tmp, *fsc_tmp, *usc_tmp; 1778 u_int64_t cur_time; 1779 int s; 1780 1781 rsc_tmp = fsc_tmp = usc_tmp = NULL; 1782 if (rsc != NULL && (rsc->m1 != 0 || rsc->m2 != 0) && 1783 cl->cl_rsc == NULL) { 1784 rsc_tmp = malloc(sizeof(struct internal_sc), 1785 M_DEVBUF, M_WAITOK); 1786 if (rsc_tmp == NULL) 1787 return (ENOMEM); 1788 } 1789 if (fsc != NULL && (fsc->m1 != 0 || fsc->m2 != 0) && 1790 cl->cl_fsc == NULL) { 1791 fsc_tmp = malloc(sizeof(struct internal_sc), 1792 M_DEVBUF, M_WAITOK); 1793 if (fsc_tmp == NULL) { 1794 free(rsc_tmp); 1795 return (ENOMEM); 1796 } 1797 } 1798 if (usc != NULL && (usc->m1 != 0 || usc->m2 != 0) && 1799 cl->cl_usc == NULL) { 1800 usc_tmp = malloc(sizeof(struct internal_sc), 1801 M_DEVBUF, M_WAITOK); 1802 if (usc_tmp == NULL) { 1803 free(rsc_tmp); 1804 free(fsc_tmp); 1805 return (ENOMEM); 1806 } 1807 } 1808 1809 cur_time = read_machclk(); 1810#ifdef __NetBSD__ 1811 s = splnet(); 1812#else 1813 s = splimp(); 1814#endif 1815 IFQ_LOCK(cl->cl_hif->hif_ifq); 1816 1817 if (rsc != NULL) { 1818 if (rsc->m1 == 0 && rsc->m2 == 0) { 1819 if (cl->cl_rsc != NULL) { 1820 if (!qempty(cl->cl_q)) 1821 hfsc_purgeq(cl); 1822 free(cl->cl_rsc, M_DEVBUF); 1823 cl->cl_rsc = NULL; 1824 } 1825 } else { 1826 if (cl->cl_rsc == NULL) 1827 cl->cl_rsc = rsc_tmp; 1828 sc2isc(rsc, cl->cl_rsc); 1829 rtsc_init(&cl->cl_deadline, cl->cl_rsc, cur_time, 1830 cl->cl_cumul); 1831 cl->cl_eligible = cl->cl_deadline; 1832 if (cl->cl_rsc->sm1 <= cl->cl_rsc->sm2) { 1833 cl->cl_eligible.dx = 0; 1834 cl->cl_eligible.dy = 0; 1835 } 1836 } 1837 } 1838 1839 if (fsc != NULL) { 1840 if (fsc->m1 == 0 && fsc->m2 == 0) { 1841 if (cl->cl_fsc != NULL) { 1842 if (!qempty(cl->cl_q)) 1843 hfsc_purgeq(cl); 1844 free(cl->cl_fsc, M_DEVBUF); 1845 cl->cl_fsc = NULL; 1846 } 1847 } else { 1848 if (cl->cl_fsc == NULL) 1849 cl->cl_fsc = fsc_tmp; 1850 sc2isc(fsc, cl->cl_fsc); 1851 rtsc_init(&cl->cl_virtual, cl->cl_fsc, cl->cl_vt, 1852 cl->cl_total); 1853 } 1854 } 1855 1856 if (usc != NULL) { 1857 if (usc->m1 == 0 && usc->m2 == 0) { 1858 if (cl->cl_usc != NULL) { 1859 free(cl->cl_usc, M_DEVBUF); 1860 cl->cl_usc = NULL; 1861 cl->cl_myf = 0; 1862 } 1863 } else { 1864 if (cl->cl_usc == NULL) 1865 cl->cl_usc = usc_tmp; 1866 sc2isc(usc, cl->cl_usc); 1867 rtsc_init(&cl->cl_ulimit, cl->cl_usc, cur_time, 1868 cl->cl_total); 1869 } 1870 } 1871 1872 if (!qempty(cl->cl_q)) { 1873 if (cl->cl_rsc != NULL) 1874 update_ed(cl, m_pktlen(qhead(cl->cl_q))); 1875 if (cl->cl_fsc != NULL) 1876 update_vf(cl, 0, cur_time); 1877 /* is this enough? */ 1878 } 1879 1880 IFQ_UNLOCK(cl->cl_hif->hif_ifq); 1881 splx(s); 1882 1883 return (0); 1884} 1885 1886/* 1887 * hfsc device interface 1888 */ 1889int 1890hfscopen(dev, flag, fmt, p) 1891 dev_t dev; 1892 int flag, fmt; 1893#if (__FreeBSD_version > 500000) 1894 struct thread *p; 1895#else 1896 struct proc *p; 1897#endif 1898{ 1899 if (machclk_freq == 0) 1900 init_machclk(); 1901 1902 if (machclk_freq == 0) { 1903 printf("hfsc: no cpu clock available!\n"); 1904 return (ENXIO); 1905 } 1906 1907 /* everything will be done when the queueing scheme is attached. */ 1908 return 0; 1909} 1910 1911int 1912hfscclose(dev, flag, fmt, p) 1913 dev_t dev; 1914 int flag, fmt; 1915#if (__FreeBSD_version > 500000) 1916 struct thread *p; 1917#else 1918 struct proc *p; 1919#endif 1920{ 1921 struct hfsc_if *hif; 1922 int err, error = 0; 1923 1924 while ((hif = hif_list) != NULL) { 1925 /* destroy all */ 1926 if (ALTQ_IS_ENABLED(hif->hif_ifq)) 1927 altq_disable(hif->hif_ifq); 1928 1929 err = altq_detach(hif->hif_ifq); 1930 if (err == 0) 1931 err = hfsc_detach(hif); 1932 if (err != 0 && error == 0) 1933 error = err; 1934 } 1935 1936 return error; 1937} 1938 1939int 1940hfscioctl(dev, cmd, addr, flag, p) 1941 dev_t dev; 1942 ioctlcmd_t cmd; 1943 caddr_t addr; 1944 int flag; 1945#if (__FreeBSD_version > 500000) 1946 struct thread *p; 1947#else 1948 struct proc *p; 1949#endif 1950{ 1951 struct hfsc_if *hif; 1952 struct hfsc_interface *ifacep; 1953 int error = 0; 1954 1955 /* check super-user privilege */ 1956 switch (cmd) { 1957 case HFSC_GETSTATS: 1958 break; 1959 default: 1960#if (__FreeBSD_version > 700000) 1961 if ((error = priv_check(p, PRIV_ALTQ_MANAGE)) != 0) 1962 return (error); 1963#elsif (__FreeBSD_version > 400000) 1964 if ((error = suser(p)) != 0) 1965 return (error); 1966#else 1967 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 1968 return (error); 1969#endif 1970 break; 1971 } 1972 1973 switch (cmd) { 1974 1975 case HFSC_IF_ATTACH: 1976 error = hfsccmd_if_attach((struct hfsc_attach *)addr); 1977 break; 1978 1979 case HFSC_IF_DETACH: 1980 error = hfsccmd_if_detach((struct hfsc_interface *)addr); 1981 break; 1982 1983 case HFSC_ENABLE: 1984 case HFSC_DISABLE: 1985 case HFSC_CLEAR_HIERARCHY: 1986 ifacep = (struct hfsc_interface *)addr; 1987 if ((hif = altq_lookup(ifacep->hfsc_ifname, 1988 ALTQT_HFSC)) == NULL) { 1989 error = EBADF; 1990 break; 1991 } 1992 1993 switch (cmd) { 1994 1995 case HFSC_ENABLE: 1996 if (hif->hif_defaultclass == NULL) { 1997#ifdef ALTQ_DEBUG 1998 printf("hfsc: no default class\n"); 1999#endif 2000 error = EINVAL; 2001 break; 2002 } 2003 error = altq_enable(hif->hif_ifq); 2004 break; 2005 2006 case HFSC_DISABLE: 2007 error = altq_disable(hif->hif_ifq); 2008 break; 2009 2010 case HFSC_CLEAR_HIERARCHY: 2011 hfsc_clear_interface(hif); 2012 break; 2013 } 2014 break; 2015 2016 case HFSC_ADD_CLASS: 2017 error = hfsccmd_add_class((struct hfsc_add_class *)addr); 2018 break; 2019 2020 case HFSC_DEL_CLASS: 2021 error = hfsccmd_delete_class((struct hfsc_delete_class *)addr); 2022 break; 2023 2024 case HFSC_MOD_CLASS: 2025 error = hfsccmd_modify_class((struct hfsc_modify_class *)addr); 2026 break; 2027 2028 case HFSC_ADD_FILTER: 2029 error = hfsccmd_add_filter((struct hfsc_add_filter *)addr); 2030 break; 2031 2032 case HFSC_DEL_FILTER: 2033 error = hfsccmd_delete_filter((struct hfsc_delete_filter *)addr); 2034 break; 2035 2036 case HFSC_GETSTATS: 2037 error = hfsccmd_class_stats((struct hfsc_class_stats *)addr); 2038 break; 2039 2040 default: 2041 error = EINVAL; 2042 break; 2043 } 2044 return error; 2045} 2046 2047static int 2048hfsccmd_if_attach(ap) 2049 struct hfsc_attach *ap; 2050{ 2051 struct hfsc_if *hif; 2052 struct ifnet *ifp; 2053 int error; 2054 2055 if ((ifp = ifunit(ap->iface.hfsc_ifname)) == NULL) 2056 return (ENXIO); 2057 2058 if ((hif = hfsc_attach(&ifp->if_snd, ap->bandwidth)) == NULL) 2059 return (ENOMEM); 2060 2061 /* 2062 * set HFSC to this ifnet structure. 2063 */ 2064 if ((error = altq_attach(&ifp->if_snd, ALTQT_HFSC, hif, 2065 hfsc_enqueue, hfsc_dequeue, hfsc_request, 2066 &hif->hif_classifier, acc_classify)) != 0) 2067 (void)hfsc_detach(hif); 2068 2069 return (error); 2070} 2071 2072static int 2073hfsccmd_if_detach(ap) 2074 struct hfsc_interface *ap; 2075{ 2076 struct hfsc_if *hif; 2077 int error; 2078 2079 if ((hif = altq_lookup(ap->hfsc_ifname, ALTQT_HFSC)) == NULL) 2080 return (EBADF); 2081 2082 if (ALTQ_IS_ENABLED(hif->hif_ifq)) 2083 altq_disable(hif->hif_ifq); 2084 2085 if ((error = altq_detach(hif->hif_ifq))) 2086 return (error); 2087 2088 return hfsc_detach(hif); 2089} 2090 2091static int 2092hfsccmd_add_class(ap) 2093 struct hfsc_add_class *ap; 2094{ 2095 struct hfsc_if *hif; 2096 struct hfsc_class *cl, *parent; 2097 int i; 2098 2099 if ((hif = altq_lookup(ap->iface.hfsc_ifname, ALTQT_HFSC)) == NULL) 2100 return (EBADF); 2101 2102 if (ap->parent_handle == HFSC_NULLCLASS_HANDLE && 2103 hif->hif_rootclass == NULL) 2104 parent = NULL; 2105 else if ((parent = clh_to_clp(hif, ap->parent_handle)) == NULL) 2106 return (EINVAL); 2107 2108 /* assign a class handle (use a free slot number for now) */ 2109 for (i = 1; i < HFSC_MAX_CLASSES; i++) 2110 if (hif->hif_class_tbl[i] == NULL) 2111 break; 2112 if (i == HFSC_MAX_CLASSES) 2113 return (EBUSY); 2114 2115 if ((cl = hfsc_class_create(hif, &ap->service_curve, NULL, NULL, 2116 parent, ap->qlimit, ap->flags, i)) == NULL) 2117 return (ENOMEM); 2118 2119 /* return a class handle to the user */ 2120 ap->class_handle = i; 2121 2122 return (0); 2123} 2124 2125static int 2126hfsccmd_delete_class(ap) 2127 struct hfsc_delete_class *ap; 2128{ 2129 struct hfsc_if *hif; 2130 struct hfsc_class *cl; 2131 2132 if ((hif = altq_lookup(ap->iface.hfsc_ifname, ALTQT_HFSC)) == NULL) 2133 return (EBADF); 2134 2135 if ((cl = clh_to_clp(hif, ap->class_handle)) == NULL) 2136 return (EINVAL); 2137 2138 return hfsc_class_destroy(cl); 2139} 2140 2141static int 2142hfsccmd_modify_class(ap) 2143 struct hfsc_modify_class *ap; 2144{ 2145 struct hfsc_if *hif; 2146 struct hfsc_class *cl; 2147 struct service_curve *rsc = NULL; 2148 struct service_curve *fsc = NULL; 2149 struct service_curve *usc = NULL; 2150 2151 if ((hif = altq_lookup(ap->iface.hfsc_ifname, ALTQT_HFSC)) == NULL) 2152 return (EBADF); 2153 2154 if ((cl = clh_to_clp(hif, ap->class_handle)) == NULL) 2155 return (EINVAL); 2156 2157 if (ap->sctype & HFSC_REALTIMESC) 2158 rsc = &ap->service_curve; 2159 if (ap->sctype & HFSC_LINKSHARINGSC) 2160 fsc = &ap->service_curve; 2161 if (ap->sctype & HFSC_UPPERLIMITSC) 2162 usc = &ap->service_curve; 2163 2164 return hfsc_class_modify(cl, rsc, fsc, usc); 2165} 2166 2167static int 2168hfsccmd_add_filter(ap) 2169 struct hfsc_add_filter *ap; 2170{ 2171 struct hfsc_if *hif; 2172 struct hfsc_class *cl; 2173 2174 if ((hif = altq_lookup(ap->iface.hfsc_ifname, ALTQT_HFSC)) == NULL) 2175 return (EBADF); 2176 2177 if ((cl = clh_to_clp(hif, ap->class_handle)) == NULL) 2178 return (EINVAL); 2179 2180 if (is_a_parent_class(cl)) { 2181#ifdef ALTQ_DEBUG 2182 printf("hfsccmd_add_filter: not a leaf class!\n"); 2183#endif 2184 return (EINVAL); 2185 } 2186 2187 return acc_add_filter(&hif->hif_classifier, &ap->filter, 2188 cl, &ap->filter_handle); 2189} 2190 2191static int 2192hfsccmd_delete_filter(ap) 2193 struct hfsc_delete_filter *ap; 2194{ 2195 struct hfsc_if *hif; 2196 2197 if ((hif = altq_lookup(ap->iface.hfsc_ifname, ALTQT_HFSC)) == NULL) 2198 return (EBADF); 2199 2200 return acc_delete_filter(&hif->hif_classifier, 2201 ap->filter_handle); 2202} 2203 2204static int 2205hfsccmd_class_stats(ap) 2206 struct hfsc_class_stats *ap; 2207{ 2208 struct hfsc_if *hif; 2209 struct hfsc_class *cl; 2210 struct hfsc_classstats stats, *usp; 2211 int n, nclasses, error; 2212 2213 if ((hif = altq_lookup(ap->iface.hfsc_ifname, ALTQT_HFSC)) == NULL) 2214 return (EBADF); 2215 2216 ap->cur_time = read_machclk(); 2217 ap->machclk_freq = machclk_freq; 2218 ap->hif_classes = hif->hif_classes; 2219 ap->hif_packets = hif->hif_packets; 2220 2221 /* skip the first N classes in the tree */ 2222 nclasses = ap->nskip; 2223 for (cl = hif->hif_rootclass, n = 0; cl != NULL && n < nclasses; 2224 cl = hfsc_nextclass(cl), n++) 2225 ; 2226 if (n != nclasses) 2227 return (EINVAL); 2228 2229 /* then, read the next N classes in the tree */ 2230 nclasses = ap->nclasses; 2231 usp = ap->stats; 2232 for (n = 0; cl != NULL && n < nclasses; cl = hfsc_nextclass(cl), n++) { 2233 2234 get_class_stats(&stats, cl); 2235 2236 if ((error = copyout((caddr_t)&stats, (caddr_t)usp++, 2237 sizeof(stats))) != 0) 2238 return (error); 2239 } 2240 2241 ap->nclasses = n; 2242 2243 return (0); 2244} 2245 2246#ifdef KLD_MODULE 2247 2248static struct altqsw hfsc_sw = 2249 {"hfsc", hfscopen, hfscclose, hfscioctl}; 2250 2251ALTQ_MODULE(altq_hfsc, ALTQT_HFSC, &hfsc_sw); 2252MODULE_DEPEND(altq_hfsc, altq_red, 1, 1, 1); 2253MODULE_DEPEND(altq_hfsc, altq_rio, 1, 1, 1); 2254 2255#endif /* KLD_MODULE */ 2256#endif /* ALTQ3_COMPAT */ 2257 2258#endif /* ALTQ_HFSC */ 2259