Annotation of sys/altq/altq_hfsc.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: altq_hfsc.c,v 1.24 2007/05/28 17:16:38 henning Exp $ */
! 2: /* $KAME: altq_hfsc.c,v 1.17 2002/11/29 07:48:33 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: #include <sys/param.h>
! 46: #include <sys/malloc.h>
! 47: #include <sys/mbuf.h>
! 48: #include <sys/socket.h>
! 49: #include <sys/systm.h>
! 50: #include <sys/errno.h>
! 51: #include <sys/queue.h>
! 52:
! 53: #include <net/if.h>
! 54: #include <netinet/in.h>
! 55:
! 56: #include <net/pfvar.h>
! 57: #include <altq/altq.h>
! 58: #include <altq/altq_hfsc.h>
! 59:
! 60: /*
! 61: * function prototypes
! 62: */
! 63: static int hfsc_clear_interface(struct hfsc_if *);
! 64: static int hfsc_request(struct ifaltq *, int, void *);
! 65: static void hfsc_purge(struct hfsc_if *);
! 66: static struct hfsc_class *hfsc_class_create(struct hfsc_if *,
! 67: struct service_curve *, struct service_curve *, struct service_curve *,
! 68: struct hfsc_class *, int, int, int);
! 69: static int hfsc_class_destroy(struct hfsc_class *);
! 70: static struct hfsc_class *hfsc_nextclass(struct hfsc_class *);
! 71: static int hfsc_enqueue(struct ifaltq *, struct mbuf *,
! 72: struct altq_pktattr *);
! 73: static struct mbuf *hfsc_dequeue(struct ifaltq *, int);
! 74:
! 75: static int hfsc_addq(struct hfsc_class *, struct mbuf *);
! 76: static struct mbuf *hfsc_getq(struct hfsc_class *);
! 77: static struct mbuf *hfsc_pollq(struct hfsc_class *);
! 78: static void hfsc_purgeq(struct hfsc_class *);
! 79:
! 80: static void update_cfmin(struct hfsc_class *);
! 81: static void set_active(struct hfsc_class *, int);
! 82: static void set_passive(struct hfsc_class *);
! 83:
! 84: static void init_ed(struct hfsc_class *, int);
! 85: static void update_ed(struct hfsc_class *, int);
! 86: static void update_d(struct hfsc_class *, int);
! 87: static void init_vf(struct hfsc_class *, int);
! 88: static void update_vf(struct hfsc_class *, int, u_int64_t);
! 89: static ellist_t *ellist_alloc(void);
! 90: static void ellist_destroy(ellist_t *);
! 91: static void ellist_insert(struct hfsc_class *);
! 92: static void ellist_remove(struct hfsc_class *);
! 93: static void ellist_update(struct hfsc_class *);
! 94: struct hfsc_class *ellist_get_mindl(ellist_t *, u_int64_t);
! 95: static actlist_t *actlist_alloc(void);
! 96: static void actlist_destroy(actlist_t *);
! 97: static void actlist_insert(struct hfsc_class *);
! 98: static void actlist_remove(struct hfsc_class *);
! 99: static void actlist_update(struct hfsc_class *);
! 100:
! 101: static struct hfsc_class *actlist_firstfit(struct hfsc_class *,
! 102: u_int64_t);
! 103:
! 104: static __inline u_int64_t seg_x2y(u_int64_t, u_int64_t);
! 105: static __inline u_int64_t seg_y2x(u_int64_t, u_int64_t);
! 106: static __inline u_int64_t m2sm(u_int);
! 107: static __inline u_int64_t m2ism(u_int);
! 108: static __inline u_int64_t d2dx(u_int);
! 109: static u_int sm2m(u_int64_t);
! 110: static u_int dx2d(u_int64_t);
! 111:
! 112: static void sc2isc(struct service_curve *, struct internal_sc *);
! 113: static void rtsc_init(struct runtime_sc *, struct internal_sc *,
! 114: u_int64_t, u_int64_t);
! 115: static u_int64_t rtsc_y2x(struct runtime_sc *, u_int64_t);
! 116: static u_int64_t rtsc_x2y(struct runtime_sc *, u_int64_t);
! 117: static void rtsc_min(struct runtime_sc *, struct internal_sc *,
! 118: u_int64_t, u_int64_t);
! 119:
! 120: static void get_class_stats(struct hfsc_classstats *,
! 121: struct hfsc_class *);
! 122: static struct hfsc_class *clh_to_clp(struct hfsc_if *, u_int32_t);
! 123:
! 124: /*
! 125: * macros
! 126: */
! 127: #define is_a_parent_class(cl) ((cl)->cl_children != NULL)
! 128:
! 129: #define HT_INFINITY 0xffffffffffffffffLL /* infinite time value */
! 130:
! 131: int
! 132: hfsc_pfattach(struct pf_altq *a)
! 133: {
! 134: struct ifnet *ifp;
! 135: int s, error;
! 136:
! 137: if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
! 138: return (EINVAL);
! 139: s = splnet();
! 140: error = altq_attach(&ifp->if_snd, ALTQT_HFSC, a->altq_disc,
! 141: hfsc_enqueue, hfsc_dequeue, hfsc_request, NULL, NULL);
! 142: splx(s);
! 143: return (error);
! 144: }
! 145:
! 146: int
! 147: hfsc_add_altq(struct pf_altq *a)
! 148: {
! 149: struct hfsc_if *hif;
! 150: struct ifnet *ifp;
! 151:
! 152: if ((ifp = ifunit(a->ifname)) == NULL)
! 153: return (EINVAL);
! 154: if (!ALTQ_IS_READY(&ifp->if_snd))
! 155: return (ENODEV);
! 156:
! 157: MALLOC(hif, struct hfsc_if *, sizeof(struct hfsc_if),
! 158: M_DEVBUF, M_WAITOK);
! 159: if (hif == NULL)
! 160: return (ENOMEM);
! 161: bzero(hif, sizeof(struct hfsc_if));
! 162:
! 163: hif->hif_eligible = ellist_alloc();
! 164: if (hif->hif_eligible == NULL) {
! 165: FREE(hif, M_DEVBUF);
! 166: return (ENOMEM);
! 167: }
! 168:
! 169: hif->hif_ifq = &ifp->if_snd;
! 170:
! 171: /* keep the state in pf_altq */
! 172: a->altq_disc = hif;
! 173:
! 174: return (0);
! 175: }
! 176:
! 177: int
! 178: hfsc_remove_altq(struct pf_altq *a)
! 179: {
! 180: struct hfsc_if *hif;
! 181:
! 182: if ((hif = a->altq_disc) == NULL)
! 183: return (EINVAL);
! 184: a->altq_disc = NULL;
! 185:
! 186: (void)hfsc_clear_interface(hif);
! 187: (void)hfsc_class_destroy(hif->hif_rootclass);
! 188:
! 189: ellist_destroy(hif->hif_eligible);
! 190:
! 191: FREE(hif, M_DEVBUF);
! 192:
! 193: return (0);
! 194: }
! 195:
! 196: int
! 197: hfsc_add_queue(struct pf_altq *a)
! 198: {
! 199: struct hfsc_if *hif;
! 200: struct hfsc_class *cl, *parent;
! 201: struct hfsc_opts *opts;
! 202: struct service_curve rtsc, lssc, ulsc;
! 203:
! 204: if ((hif = a->altq_disc) == NULL)
! 205: return (EINVAL);
! 206:
! 207: opts = &a->pq_u.hfsc_opts;
! 208:
! 209: if (a->parent_qid == HFSC_NULLCLASS_HANDLE &&
! 210: hif->hif_rootclass == NULL)
! 211: parent = NULL;
! 212: else if ((parent = clh_to_clp(hif, a->parent_qid)) == NULL)
! 213: return (EINVAL);
! 214:
! 215: if (a->qid == 0)
! 216: return (EINVAL);
! 217:
! 218: if (clh_to_clp(hif, a->qid) != NULL)
! 219: return (EBUSY);
! 220:
! 221: rtsc.m1 = opts->rtsc_m1;
! 222: rtsc.d = opts->rtsc_d;
! 223: rtsc.m2 = opts->rtsc_m2;
! 224: lssc.m1 = opts->lssc_m1;
! 225: lssc.d = opts->lssc_d;
! 226: lssc.m2 = opts->lssc_m2;
! 227: ulsc.m1 = opts->ulsc_m1;
! 228: ulsc.d = opts->ulsc_d;
! 229: ulsc.m2 = opts->ulsc_m2;
! 230:
! 231: cl = hfsc_class_create(hif, &rtsc, &lssc, &ulsc,
! 232: parent, a->qlimit, opts->flags, a->qid);
! 233: if (cl == NULL)
! 234: return (ENOMEM);
! 235:
! 236: return (0);
! 237: }
! 238:
! 239: int
! 240: hfsc_remove_queue(struct pf_altq *a)
! 241: {
! 242: struct hfsc_if *hif;
! 243: struct hfsc_class *cl;
! 244:
! 245: if ((hif = a->altq_disc) == NULL)
! 246: return (EINVAL);
! 247:
! 248: if ((cl = clh_to_clp(hif, a->qid)) == NULL)
! 249: return (EINVAL);
! 250:
! 251: return (hfsc_class_destroy(cl));
! 252: }
! 253:
! 254: int
! 255: hfsc_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
! 256: {
! 257: struct hfsc_if *hif;
! 258: struct hfsc_class *cl;
! 259: struct hfsc_classstats stats;
! 260: int error = 0;
! 261:
! 262: if ((hif = altq_lookup(a->ifname, ALTQT_HFSC)) == NULL)
! 263: return (EBADF);
! 264:
! 265: if ((cl = clh_to_clp(hif, a->qid)) == NULL)
! 266: return (EINVAL);
! 267:
! 268: if (*nbytes < sizeof(stats))
! 269: return (EINVAL);
! 270:
! 271: get_class_stats(&stats, cl);
! 272:
! 273: if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
! 274: return (error);
! 275: *nbytes = sizeof(stats);
! 276: return (0);
! 277: }
! 278:
! 279: /*
! 280: * bring the interface back to the initial state by discarding
! 281: * all the filters and classes except the root class.
! 282: */
! 283: static int
! 284: hfsc_clear_interface(struct hfsc_if *hif)
! 285: {
! 286: struct hfsc_class *cl;
! 287:
! 288: /* clear out the classes */
! 289: while (hif->hif_rootclass != NULL &&
! 290: (cl = hif->hif_rootclass->cl_children) != NULL) {
! 291: /*
! 292: * remove the first leaf class found in the hierarchy
! 293: * then start over
! 294: */
! 295: for (; cl != NULL; cl = hfsc_nextclass(cl)) {
! 296: if (!is_a_parent_class(cl)) {
! 297: (void)hfsc_class_destroy(cl);
! 298: break;
! 299: }
! 300: }
! 301: }
! 302:
! 303: return (0);
! 304: }
! 305:
! 306: static int
! 307: hfsc_request(struct ifaltq *ifq, int req, void *arg)
! 308: {
! 309: struct hfsc_if *hif = (struct hfsc_if *)ifq->altq_disc;
! 310:
! 311: switch (req) {
! 312: case ALTRQ_PURGE:
! 313: hfsc_purge(hif);
! 314: break;
! 315: }
! 316: return (0);
! 317: }
! 318:
! 319: /* discard all the queued packets on the interface */
! 320: static void
! 321: hfsc_purge(struct hfsc_if *hif)
! 322: {
! 323: struct hfsc_class *cl;
! 324:
! 325: for (cl = hif->hif_rootclass; cl != NULL; cl = hfsc_nextclass(cl))
! 326: if (!qempty(cl->cl_q))
! 327: hfsc_purgeq(cl);
! 328: if (ALTQ_IS_ENABLED(hif->hif_ifq))
! 329: hif->hif_ifq->ifq_len = 0;
! 330: }
! 331:
! 332: struct hfsc_class *
! 333: hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc,
! 334: struct service_curve *fsc, struct service_curve *usc,
! 335: struct hfsc_class *parent, int qlimit, int flags, int qid)
! 336: {
! 337: struct hfsc_class *cl, *p;
! 338: int i, s;
! 339:
! 340: if (hif->hif_classes >= HFSC_MAX_CLASSES)
! 341: return (NULL);
! 342:
! 343: #ifndef ALTQ_RED
! 344: if (flags & HFCF_RED) {
! 345: #ifdef ALTQ_DEBUG
! 346: printf("hfsc_class_create: RED not configured for HFSC!\n");
! 347: #endif
! 348: return (NULL);
! 349: }
! 350: #endif
! 351:
! 352: MALLOC(cl, struct hfsc_class *, sizeof(struct hfsc_class),
! 353: M_DEVBUF, M_WAITOK);
! 354: if (cl == NULL)
! 355: return (NULL);
! 356: bzero(cl, sizeof(struct hfsc_class));
! 357:
! 358: MALLOC(cl->cl_q, class_queue_t *, sizeof(class_queue_t),
! 359: M_DEVBUF, M_WAITOK);
! 360: if (cl->cl_q == NULL)
! 361: goto err_ret;
! 362: bzero(cl->cl_q, sizeof(class_queue_t));
! 363:
! 364: cl->cl_actc = actlist_alloc();
! 365: if (cl->cl_actc == NULL)
! 366: goto err_ret;
! 367:
! 368: if (qlimit == 0)
! 369: qlimit = 50; /* use default */
! 370: qlimit(cl->cl_q) = qlimit;
! 371: qtype(cl->cl_q) = Q_DROPTAIL;
! 372: qlen(cl->cl_q) = 0;
! 373: cl->cl_flags = flags;
! 374: #ifdef ALTQ_RED
! 375: if (flags & (HFCF_RED|HFCF_RIO)) {
! 376: int red_flags, red_pkttime;
! 377: u_int m2;
! 378:
! 379: m2 = 0;
! 380: if (rsc != NULL && rsc->m2 > m2)
! 381: m2 = rsc->m2;
! 382: if (fsc != NULL && fsc->m2 > m2)
! 383: m2 = fsc->m2;
! 384: if (usc != NULL && usc->m2 > m2)
! 385: m2 = usc->m2;
! 386:
! 387: red_flags = 0;
! 388: if (flags & HFCF_ECN)
! 389: red_flags |= REDF_ECN;
! 390: #ifdef ALTQ_RIO
! 391: if (flags & HFCF_CLEARDSCP)
! 392: red_flags |= RIOF_CLEARDSCP;
! 393: #endif
! 394: if (m2 < 8)
! 395: red_pkttime = 1000 * 1000 * 1000; /* 1 sec */
! 396: else
! 397: red_pkttime = (int64_t)hif->hif_ifq->altq_ifp->if_mtu
! 398: * 1000 * 1000 * 1000 / (m2 / 8);
! 399: if (flags & HFCF_RED) {
! 400: cl->cl_red = red_alloc(0, 0,
! 401: qlimit(cl->cl_q) * 10/100,
! 402: qlimit(cl->cl_q) * 30/100,
! 403: red_flags, red_pkttime);
! 404: if (cl->cl_red != NULL)
! 405: qtype(cl->cl_q) = Q_RED;
! 406: }
! 407: #ifdef ALTQ_RIO
! 408: else {
! 409: cl->cl_red = (red_t *)rio_alloc(0, NULL,
! 410: red_flags, red_pkttime);
! 411: if (cl->cl_red != NULL)
! 412: qtype(cl->cl_q) = Q_RIO;
! 413: }
! 414: #endif
! 415: }
! 416: #endif /* ALTQ_RED */
! 417:
! 418: if (rsc != NULL && (rsc->m1 != 0 || rsc->m2 != 0)) {
! 419: MALLOC(cl->cl_rsc, struct internal_sc *,
! 420: sizeof(struct internal_sc), M_DEVBUF, M_WAITOK);
! 421: if (cl->cl_rsc == NULL)
! 422: goto err_ret;
! 423: sc2isc(rsc, cl->cl_rsc);
! 424: rtsc_init(&cl->cl_deadline, cl->cl_rsc, 0, 0);
! 425: rtsc_init(&cl->cl_eligible, cl->cl_rsc, 0, 0);
! 426: }
! 427: if (fsc != NULL && (fsc->m1 != 0 || fsc->m2 != 0)) {
! 428: MALLOC(cl->cl_fsc, struct internal_sc *,
! 429: sizeof(struct internal_sc), M_DEVBUF, M_WAITOK);
! 430: if (cl->cl_fsc == NULL)
! 431: goto err_ret;
! 432: sc2isc(fsc, cl->cl_fsc);
! 433: rtsc_init(&cl->cl_virtual, cl->cl_fsc, 0, 0);
! 434: }
! 435: if (usc != NULL && (usc->m1 != 0 || usc->m2 != 0)) {
! 436: MALLOC(cl->cl_usc, struct internal_sc *,
! 437: sizeof(struct internal_sc), M_DEVBUF, M_WAITOK);
! 438: if (cl->cl_usc == NULL)
! 439: goto err_ret;
! 440: sc2isc(usc, cl->cl_usc);
! 441: rtsc_init(&cl->cl_ulimit, cl->cl_usc, 0, 0);
! 442: }
! 443:
! 444: cl->cl_id = hif->hif_classid++;
! 445: cl->cl_handle = qid;
! 446: cl->cl_hif = hif;
! 447: cl->cl_parent = parent;
! 448:
! 449: s = splnet();
! 450: hif->hif_classes++;
! 451:
! 452: /*
! 453: * find a free slot in the class table. if the slot matching
! 454: * the lower bits of qid is free, use this slot. otherwise,
! 455: * use the first free slot.
! 456: */
! 457: i = qid % HFSC_MAX_CLASSES;
! 458: if (hif->hif_class_tbl[i] == NULL)
! 459: hif->hif_class_tbl[i] = cl;
! 460: else {
! 461: for (i = 0; i < HFSC_MAX_CLASSES; i++)
! 462: if (hif->hif_class_tbl[i] == NULL) {
! 463: hif->hif_class_tbl[i] = cl;
! 464: break;
! 465: }
! 466: if (i == HFSC_MAX_CLASSES) {
! 467: splx(s);
! 468: goto err_ret;
! 469: }
! 470: }
! 471:
! 472: if (flags & HFCF_DEFAULTCLASS)
! 473: hif->hif_defaultclass = cl;
! 474:
! 475: if (parent == NULL) {
! 476: /* this is root class */
! 477: hif->hif_rootclass = cl;
! 478: } else {
! 479: /* add this class to the children list of the parent */
! 480: if ((p = parent->cl_children) == NULL)
! 481: parent->cl_children = cl;
! 482: else {
! 483: while (p->cl_siblings != NULL)
! 484: p = p->cl_siblings;
! 485: p->cl_siblings = cl;
! 486: }
! 487: }
! 488: splx(s);
! 489:
! 490: return (cl);
! 491:
! 492: err_ret:
! 493: if (cl->cl_actc != NULL)
! 494: actlist_destroy(cl->cl_actc);
! 495: if (cl->cl_red != NULL) {
! 496: #ifdef ALTQ_RIO
! 497: if (q_is_rio(cl->cl_q))
! 498: rio_destroy((rio_t *)cl->cl_red);
! 499: #endif
! 500: #ifdef ALTQ_RED
! 501: if (q_is_red(cl->cl_q))
! 502: red_destroy(cl->cl_red);
! 503: #endif
! 504: }
! 505: if (cl->cl_fsc != NULL)
! 506: FREE(cl->cl_fsc, M_DEVBUF);
! 507: if (cl->cl_rsc != NULL)
! 508: FREE(cl->cl_rsc, M_DEVBUF);
! 509: if (cl->cl_usc != NULL)
! 510: FREE(cl->cl_usc, M_DEVBUF);
! 511: if (cl->cl_q != NULL)
! 512: FREE(cl->cl_q, M_DEVBUF);
! 513: FREE(cl, M_DEVBUF);
! 514: return (NULL);
! 515: }
! 516:
! 517: static int
! 518: hfsc_class_destroy(struct hfsc_class *cl)
! 519: {
! 520: int i, s;
! 521:
! 522: if (cl == NULL)
! 523: return (0);
! 524:
! 525: if (is_a_parent_class(cl))
! 526: return (EBUSY);
! 527:
! 528: s = splnet();
! 529:
! 530: if (!qempty(cl->cl_q))
! 531: hfsc_purgeq(cl);
! 532:
! 533: if (cl->cl_parent == NULL) {
! 534: /* this is root class */
! 535: } else {
! 536: struct hfsc_class *p = cl->cl_parent->cl_children;
! 537:
! 538: if (p == cl)
! 539: cl->cl_parent->cl_children = cl->cl_siblings;
! 540: else do {
! 541: if (p->cl_siblings == cl) {
! 542: p->cl_siblings = cl->cl_siblings;
! 543: break;
! 544: }
! 545: } while ((p = p->cl_siblings) != NULL);
! 546: ASSERT(p != NULL);
! 547: }
! 548:
! 549: for (i = 0; i < HFSC_MAX_CLASSES; i++)
! 550: if (cl->cl_hif->hif_class_tbl[i] == cl) {
! 551: cl->cl_hif->hif_class_tbl[i] = NULL;
! 552: break;
! 553: }
! 554:
! 555: cl->cl_hif->hif_classes--;
! 556: splx(s);
! 557:
! 558: actlist_destroy(cl->cl_actc);
! 559:
! 560: if (cl->cl_red != NULL) {
! 561: #ifdef ALTQ_RIO
! 562: if (q_is_rio(cl->cl_q))
! 563: rio_destroy((rio_t *)cl->cl_red);
! 564: #endif
! 565: #ifdef ALTQ_RED
! 566: if (q_is_red(cl->cl_q))
! 567: red_destroy(cl->cl_red);
! 568: #endif
! 569: }
! 570:
! 571: if (cl == cl->cl_hif->hif_rootclass)
! 572: cl->cl_hif->hif_rootclass = NULL;
! 573: if (cl == cl->cl_hif->hif_defaultclass)
! 574: cl->cl_hif->hif_defaultclass = NULL;
! 575:
! 576: if (cl->cl_usc != NULL)
! 577: FREE(cl->cl_usc, M_DEVBUF);
! 578: if (cl->cl_fsc != NULL)
! 579: FREE(cl->cl_fsc, M_DEVBUF);
! 580: if (cl->cl_rsc != NULL)
! 581: FREE(cl->cl_rsc, M_DEVBUF);
! 582: FREE(cl->cl_q, M_DEVBUF);
! 583: FREE(cl, M_DEVBUF);
! 584:
! 585: return (0);
! 586: }
! 587:
! 588: /*
! 589: * hfsc_nextclass returns the next class in the tree.
! 590: * usage:
! 591: * for (cl = hif->hif_rootclass; cl != NULL; cl = hfsc_nextclass(cl))
! 592: * do_something;
! 593: */
! 594: static struct hfsc_class *
! 595: hfsc_nextclass(struct hfsc_class *cl)
! 596: {
! 597: if (cl->cl_children != NULL)
! 598: cl = cl->cl_children;
! 599: else if (cl->cl_siblings != NULL)
! 600: cl = cl->cl_siblings;
! 601: else {
! 602: while ((cl = cl->cl_parent) != NULL)
! 603: if (cl->cl_siblings) {
! 604: cl = cl->cl_siblings;
! 605: break;
! 606: }
! 607: }
! 608:
! 609: return (cl);
! 610: }
! 611:
! 612: /*
! 613: * hfsc_enqueue is an enqueue function to be registered to
! 614: * (*altq_enqueue) in struct ifaltq.
! 615: */
! 616: static int
! 617: hfsc_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
! 618: {
! 619: struct hfsc_if *hif = (struct hfsc_if *)ifq->altq_disc;
! 620: struct hfsc_class *cl;
! 621: int len;
! 622:
! 623: /* grab class set by classifier */
! 624: if ((m->m_flags & M_PKTHDR) == 0) {
! 625: /* should not happen */
! 626: printf("altq: packet for %s does not have pkthdr\n",
! 627: ifq->altq_ifp->if_xname);
! 628: m_freem(m);
! 629: return (ENOBUFS);
! 630: }
! 631: if ((cl = clh_to_clp(hif, m->m_pkthdr.pf.qid)) == NULL ||
! 632: is_a_parent_class(cl)) {
! 633: cl = hif->hif_defaultclass;
! 634: if (cl == NULL) {
! 635: m_freem(m);
! 636: return (ENOBUFS);
! 637: }
! 638: cl->cl_pktattr = NULL;
! 639: }
! 640:
! 641: len = m_pktlen(m);
! 642: if (hfsc_addq(cl, m) != 0) {
! 643: /* drop occurred. mbuf was freed in hfsc_addq. */
! 644: PKTCNTR_ADD(&cl->cl_stats.drop_cnt, len);
! 645: return (ENOBUFS);
! 646: }
! 647: IFQ_INC_LEN(ifq);
! 648: cl->cl_hif->hif_packets++;
! 649:
! 650: /* successfully queued. */
! 651: if (qlen(cl->cl_q) == 1)
! 652: set_active(cl, m_pktlen(m));
! 653:
! 654: return (0);
! 655: }
! 656:
! 657: /*
! 658: * hfsc_dequeue is a dequeue function to be registered to
! 659: * (*altq_dequeue) in struct ifaltq.
! 660: *
! 661: * note: ALTDQ_POLL returns the next packet without removing the packet
! 662: * from the queue. ALTDQ_REMOVE is a normal dequeue operation.
! 663: * ALTDQ_REMOVE must return the same packet if called immediately
! 664: * after ALTDQ_POLL.
! 665: */
! 666: static struct mbuf *
! 667: hfsc_dequeue(struct ifaltq *ifq, int op)
! 668: {
! 669: struct hfsc_if *hif = (struct hfsc_if *)ifq->altq_disc;
! 670: struct hfsc_class *cl;
! 671: struct mbuf *m;
! 672: int len, next_len;
! 673: int realtime = 0;
! 674: u_int64_t cur_time;
! 675:
! 676: if (hif->hif_packets == 0)
! 677: /* no packet in the tree */
! 678: return (NULL);
! 679:
! 680: cur_time = read_machclk();
! 681:
! 682: if (op == ALTDQ_REMOVE && hif->hif_pollcache != NULL) {
! 683:
! 684: cl = hif->hif_pollcache;
! 685: hif->hif_pollcache = NULL;
! 686: /* check if the class was scheduled by real-time criteria */
! 687: if (cl->cl_rsc != NULL)
! 688: realtime = (cl->cl_e <= cur_time);
! 689: } else {
! 690: /*
! 691: * if there are eligible classes, use real-time criteria.
! 692: * find the class with the minimum deadline among
! 693: * the eligible classes.
! 694: */
! 695: if ((cl = ellist_get_mindl(hif->hif_eligible, cur_time))
! 696: != NULL) {
! 697: realtime = 1;
! 698: } else {
! 699: #ifdef ALTQ_DEBUG
! 700: int fits = 0;
! 701: #endif
! 702: /*
! 703: * use link-sharing criteria
! 704: * get the class with the minimum vt in the hierarchy
! 705: */
! 706: cl = hif->hif_rootclass;
! 707: while (is_a_parent_class(cl)) {
! 708:
! 709: cl = actlist_firstfit(cl, cur_time);
! 710: if (cl == NULL) {
! 711: #ifdef ALTQ_DEBUG
! 712: if (fits > 0)
! 713: printf("%d fit but none found\n",fits);
! 714: #endif
! 715: return (NULL);
! 716: }
! 717: /*
! 718: * update parent's cl_cvtmin.
! 719: * don't update if the new vt is smaller.
! 720: */
! 721: if (cl->cl_parent->cl_cvtmin < cl->cl_vt)
! 722: cl->cl_parent->cl_cvtmin = cl->cl_vt;
! 723: #ifdef ALTQ_DEBUG
! 724: fits++;
! 725: #endif
! 726: }
! 727: }
! 728:
! 729: if (op == ALTDQ_POLL) {
! 730: hif->hif_pollcache = cl;
! 731: m = hfsc_pollq(cl);
! 732: return (m);
! 733: }
! 734: }
! 735:
! 736: m = hfsc_getq(cl);
! 737: if (m == NULL)
! 738: panic("hfsc_dequeue:");
! 739: len = m_pktlen(m);
! 740: cl->cl_hif->hif_packets--;
! 741: IFQ_DEC_LEN(ifq);
! 742: PKTCNTR_ADD(&cl->cl_stats.xmit_cnt, len);
! 743:
! 744: update_vf(cl, len, cur_time);
! 745: if (realtime)
! 746: cl->cl_cumul += len;
! 747:
! 748: if (!qempty(cl->cl_q)) {
! 749: if (cl->cl_rsc != NULL) {
! 750: /* update ed */
! 751: next_len = m_pktlen(qhead(cl->cl_q));
! 752:
! 753: if (realtime)
! 754: update_ed(cl, next_len);
! 755: else
! 756: update_d(cl, next_len);
! 757: }
! 758: } else {
! 759: /* the class becomes passive */
! 760: set_passive(cl);
! 761: }
! 762:
! 763: return (m);
! 764: }
! 765:
! 766: static int
! 767: hfsc_addq(struct hfsc_class *cl, struct mbuf *m)
! 768: {
! 769:
! 770: #ifdef ALTQ_RIO
! 771: if (q_is_rio(cl->cl_q))
! 772: return rio_addq((rio_t *)cl->cl_red, cl->cl_q,
! 773: m, cl->cl_pktattr);
! 774: #endif
! 775: #ifdef ALTQ_RED
! 776: if (q_is_red(cl->cl_q))
! 777: return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr);
! 778: #endif
! 779: if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) {
! 780: m_freem(m);
! 781: return (-1);
! 782: }
! 783:
! 784: if (cl->cl_flags & HFCF_CLEARDSCP)
! 785: write_dsfield(m, cl->cl_pktattr, 0);
! 786:
! 787: _addq(cl->cl_q, m);
! 788:
! 789: return (0);
! 790: }
! 791:
! 792: static struct mbuf *
! 793: hfsc_getq(struct hfsc_class *cl)
! 794: {
! 795: #ifdef ALTQ_RIO
! 796: if (q_is_rio(cl->cl_q))
! 797: return rio_getq((rio_t *)cl->cl_red, cl->cl_q);
! 798: #endif
! 799: #ifdef ALTQ_RED
! 800: if (q_is_red(cl->cl_q))
! 801: return red_getq(cl->cl_red, cl->cl_q);
! 802: #endif
! 803: return _getq(cl->cl_q);
! 804: }
! 805:
! 806: static struct mbuf *
! 807: hfsc_pollq(struct hfsc_class *cl)
! 808: {
! 809: return qhead(cl->cl_q);
! 810: }
! 811:
! 812: static void
! 813: hfsc_purgeq(struct hfsc_class *cl)
! 814: {
! 815: struct mbuf *m;
! 816:
! 817: if (qempty(cl->cl_q))
! 818: return;
! 819:
! 820: while ((m = _getq(cl->cl_q)) != NULL) {
! 821: PKTCNTR_ADD(&cl->cl_stats.drop_cnt, m_pktlen(m));
! 822: m_freem(m);
! 823: cl->cl_hif->hif_packets--;
! 824: IFQ_DEC_LEN(cl->cl_hif->hif_ifq);
! 825: }
! 826: ASSERT(qlen(cl->cl_q) == 0);
! 827:
! 828: update_vf(cl, 0, 0); /* remove cl from the actlist */
! 829: set_passive(cl);
! 830: }
! 831:
! 832: static void
! 833: set_active(struct hfsc_class *cl, int len)
! 834: {
! 835: if (cl->cl_rsc != NULL)
! 836: init_ed(cl, len);
! 837: if (cl->cl_fsc != NULL)
! 838: init_vf(cl, len);
! 839:
! 840: cl->cl_stats.period++;
! 841: }
! 842:
! 843: static void
! 844: set_passive(struct hfsc_class *cl)
! 845: {
! 846: if (cl->cl_rsc != NULL)
! 847: ellist_remove(cl);
! 848:
! 849: /*
! 850: * actlist is now handled in update_vf() so that update_vf(cl, 0, 0)
! 851: * needs to be called explicitly to remove a class from actlist
! 852: */
! 853: }
! 854:
! 855: static void
! 856: init_ed(struct hfsc_class *cl, int next_len)
! 857: {
! 858: u_int64_t cur_time;
! 859:
! 860: cur_time = read_machclk();
! 861:
! 862: /* update the deadline curve */
! 863: rtsc_min(&cl->cl_deadline, cl->cl_rsc, cur_time, cl->cl_cumul);
! 864:
! 865: /*
! 866: * update the eligible curve.
! 867: * for concave, it is equal to the deadline curve.
! 868: * for convex, it is a linear curve with slope m2.
! 869: */
! 870: cl->cl_eligible = cl->cl_deadline;
! 871: if (cl->cl_rsc->sm1 <= cl->cl_rsc->sm2) {
! 872: cl->cl_eligible.dx = 0;
! 873: cl->cl_eligible.dy = 0;
! 874: }
! 875:
! 876: /* compute e and d */
! 877: cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul);
! 878: cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len);
! 879:
! 880: ellist_insert(cl);
! 881: }
! 882:
! 883: static void
! 884: update_ed(struct hfsc_class *cl, int next_len)
! 885: {
! 886: cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul);
! 887: cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len);
! 888:
! 889: ellist_update(cl);
! 890: }
! 891:
! 892: static void
! 893: update_d(struct hfsc_class *cl, int next_len)
! 894: {
! 895: cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len);
! 896: }
! 897:
! 898: static void
! 899: init_vf(struct hfsc_class *cl, int len)
! 900: {
! 901: struct hfsc_class *max_cl, *p;
! 902: u_int64_t vt, f, cur_time;
! 903: int go_active;
! 904:
! 905: cur_time = 0;
! 906: go_active = 1;
! 907: for ( ; cl->cl_parent != NULL; cl = cl->cl_parent) {
! 908:
! 909: if (go_active && cl->cl_nactive++ == 0)
! 910: go_active = 1;
! 911: else
! 912: go_active = 0;
! 913:
! 914: if (go_active) {
! 915: max_cl = actlist_last(cl->cl_parent->cl_actc);
! 916: if (max_cl != NULL) {
! 917: /*
! 918: * set vt to the average of the min and max
! 919: * classes. if the parent's period didn't
! 920: * change, don't decrease vt of the class.
! 921: */
! 922: vt = max_cl->cl_vt;
! 923: if (cl->cl_parent->cl_cvtmin != 0)
! 924: vt = (cl->cl_parent->cl_cvtmin + vt)/2;
! 925:
! 926: if (cl->cl_parent->cl_vtperiod !=
! 927: cl->cl_parentperiod || vt > cl->cl_vt)
! 928: cl->cl_vt = vt;
! 929: } else {
! 930: /*
! 931: * first child for a new parent backlog period.
! 932: * add parent's cvtmax to vtoff of children
! 933: * to make a new vt (vtoff + vt) larger than
! 934: * the vt in the last period for all children.
! 935: */
! 936: vt = cl->cl_parent->cl_cvtmax;
! 937: for (p = cl->cl_parent->cl_children; p != NULL;
! 938: p = p->cl_siblings)
! 939: p->cl_vtoff += vt;
! 940: cl->cl_vt = 0;
! 941: cl->cl_parent->cl_cvtmax = 0;
! 942: cl->cl_parent->cl_cvtmin = 0;
! 943: }
! 944: cl->cl_initvt = cl->cl_vt;
! 945:
! 946: /* update the virtual curve */
! 947: vt = cl->cl_vt + cl->cl_vtoff;
! 948: rtsc_min(&cl->cl_virtual, cl->cl_fsc, vt, cl->cl_total);
! 949: if (cl->cl_virtual.x == vt) {
! 950: cl->cl_virtual.x -= cl->cl_vtoff;
! 951: cl->cl_vtoff = 0;
! 952: }
! 953: cl->cl_vtadj = 0;
! 954:
! 955: cl->cl_vtperiod++; /* increment vt period */
! 956: cl->cl_parentperiod = cl->cl_parent->cl_vtperiod;
! 957: if (cl->cl_parent->cl_nactive == 0)
! 958: cl->cl_parentperiod++;
! 959: cl->cl_f = 0;
! 960:
! 961: actlist_insert(cl);
! 962:
! 963: if (cl->cl_usc != NULL) {
! 964: /* class has upper limit curve */
! 965: if (cur_time == 0)
! 966: cur_time = read_machclk();
! 967:
! 968: /* update the ulimit curve */
! 969: rtsc_min(&cl->cl_ulimit, cl->cl_usc, cur_time,
! 970: cl->cl_total);
! 971: /* compute myf */
! 972: cl->cl_myf = rtsc_y2x(&cl->cl_ulimit,
! 973: cl->cl_total);
! 974: cl->cl_myfadj = 0;
! 975: }
! 976: }
! 977:
! 978: if (cl->cl_myf > cl->cl_cfmin)
! 979: f = cl->cl_myf;
! 980: else
! 981: f = cl->cl_cfmin;
! 982: if (f != cl->cl_f) {
! 983: cl->cl_f = f;
! 984: update_cfmin(cl->cl_parent);
! 985: }
! 986: }
! 987: }
! 988:
! 989: static void
! 990: update_vf(struct hfsc_class *cl, int len, u_int64_t cur_time)
! 991: {
! 992: u_int64_t f, myf_bound, delta;
! 993: int go_passive;
! 994:
! 995: go_passive = qempty(cl->cl_q);
! 996:
! 997: for (; cl->cl_parent != NULL; cl = cl->cl_parent) {
! 998:
! 999: cl->cl_total += len;
! 1000:
! 1001: if (cl->cl_fsc == NULL || cl->cl_nactive == 0)
! 1002: continue;
! 1003:
! 1004: if (go_passive && --cl->cl_nactive == 0)
! 1005: go_passive = 1;
! 1006: else
! 1007: go_passive = 0;
! 1008:
! 1009: if (go_passive) {
! 1010: /* no more active child, going passive */
! 1011:
! 1012: /* update cvtmax of the parent class */
! 1013: if (cl->cl_vt > cl->cl_parent->cl_cvtmax)
! 1014: cl->cl_parent->cl_cvtmax = cl->cl_vt;
! 1015:
! 1016: /* remove this class from the vt list */
! 1017: actlist_remove(cl);
! 1018:
! 1019: update_cfmin(cl->cl_parent);
! 1020:
! 1021: continue;
! 1022: }
! 1023:
! 1024: /*
! 1025: * update vt and f
! 1026: */
! 1027: cl->cl_vt = rtsc_y2x(&cl->cl_virtual, cl->cl_total)
! 1028: - cl->cl_vtoff + cl->cl_vtadj;
! 1029:
! 1030: /*
! 1031: * if vt of the class is smaller than cvtmin,
! 1032: * the class was skipped in the past due to non-fit.
! 1033: * if so, we need to adjust vtadj.
! 1034: */
! 1035: if (cl->cl_vt < cl->cl_parent->cl_cvtmin) {
! 1036: cl->cl_vtadj += cl->cl_parent->cl_cvtmin - cl->cl_vt;
! 1037: cl->cl_vt = cl->cl_parent->cl_cvtmin;
! 1038: }
! 1039:
! 1040: /* update the vt list */
! 1041: actlist_update(cl);
! 1042:
! 1043: if (cl->cl_usc != NULL) {
! 1044: cl->cl_myf = cl->cl_myfadj
! 1045: + rtsc_y2x(&cl->cl_ulimit, cl->cl_total);
! 1046:
! 1047: /*
! 1048: * if myf lags behind by more than one clock tick
! 1049: * from the current time, adjust myfadj to prevent
! 1050: * a rate-limited class from going greedy.
! 1051: * in a steady state under rate-limiting, myf
! 1052: * fluctuates within one clock tick.
! 1053: */
! 1054: myf_bound = cur_time - machclk_per_tick;
! 1055: if (cl->cl_myf < myf_bound) {
! 1056: delta = cur_time - cl->cl_myf;
! 1057: cl->cl_myfadj += delta;
! 1058: cl->cl_myf += delta;
! 1059: }
! 1060: }
! 1061:
! 1062: /* cl_f is max(cl_myf, cl_cfmin) */
! 1063: if (cl->cl_myf > cl->cl_cfmin)
! 1064: f = cl->cl_myf;
! 1065: else
! 1066: f = cl->cl_cfmin;
! 1067: if (f != cl->cl_f) {
! 1068: cl->cl_f = f;
! 1069: update_cfmin(cl->cl_parent);
! 1070: }
! 1071: }
! 1072: }
! 1073:
! 1074: static void
! 1075: update_cfmin(struct hfsc_class *cl)
! 1076: {
! 1077: struct hfsc_class *p;
! 1078: u_int64_t cfmin;
! 1079:
! 1080: if (TAILQ_EMPTY(cl->cl_actc)) {
! 1081: cl->cl_cfmin = 0;
! 1082: return;
! 1083: }
! 1084: cfmin = HT_INFINITY;
! 1085: TAILQ_FOREACH(p, cl->cl_actc, cl_actlist) {
! 1086: if (p->cl_f == 0) {
! 1087: cl->cl_cfmin = 0;
! 1088: return;
! 1089: }
! 1090: if (p->cl_f < cfmin)
! 1091: cfmin = p->cl_f;
! 1092: }
! 1093: cl->cl_cfmin = cfmin;
! 1094: }
! 1095:
! 1096: /*
! 1097: * TAILQ based ellist and actlist implementation
! 1098: * (ion wanted to make a calendar queue based implementation)
! 1099: */
! 1100: /*
! 1101: * eligible list holds backlogged classes being sorted by their eligible times.
! 1102: * there is one eligible list per interface.
! 1103: */
! 1104:
! 1105: static ellist_t *
! 1106: ellist_alloc(void)
! 1107: {
! 1108: ellist_t *head;
! 1109:
! 1110: MALLOC(head, ellist_t *, sizeof(ellist_t), M_DEVBUF, M_WAITOK);
! 1111: TAILQ_INIT(head);
! 1112: return (head);
! 1113: }
! 1114:
! 1115: static void
! 1116: ellist_destroy(ellist_t *head)
! 1117: {
! 1118: FREE(head, M_DEVBUF);
! 1119: }
! 1120:
! 1121: static void
! 1122: ellist_insert(struct hfsc_class *cl)
! 1123: {
! 1124: struct hfsc_if *hif = cl->cl_hif;
! 1125: struct hfsc_class *p;
! 1126:
! 1127: /* check the last entry first */
! 1128: if ((p = TAILQ_LAST(hif->hif_eligible, _eligible)) == NULL ||
! 1129: p->cl_e <= cl->cl_e) {
! 1130: TAILQ_INSERT_TAIL(hif->hif_eligible, cl, cl_ellist);
! 1131: return;
! 1132: }
! 1133:
! 1134: TAILQ_FOREACH(p, hif->hif_eligible, cl_ellist) {
! 1135: if (cl->cl_e < p->cl_e) {
! 1136: TAILQ_INSERT_BEFORE(p, cl, cl_ellist);
! 1137: return;
! 1138: }
! 1139: }
! 1140: ASSERT(0); /* should not reach here */
! 1141: }
! 1142:
! 1143: static void
! 1144: ellist_remove(struct hfsc_class *cl)
! 1145: {
! 1146: struct hfsc_if *hif = cl->cl_hif;
! 1147:
! 1148: TAILQ_REMOVE(hif->hif_eligible, cl, cl_ellist);
! 1149: }
! 1150:
! 1151: static void
! 1152: ellist_update(struct hfsc_class *cl)
! 1153: {
! 1154: struct hfsc_if *hif = cl->cl_hif;
! 1155: struct hfsc_class *p, *last;
! 1156:
! 1157: /*
! 1158: * the eligible time of a class increases monotonically.
! 1159: * if the next entry has a larger eligible time, nothing to do.
! 1160: */
! 1161: p = TAILQ_NEXT(cl, cl_ellist);
! 1162: if (p == NULL || cl->cl_e <= p->cl_e)
! 1163: return;
! 1164:
! 1165: /* check the last entry */
! 1166: last = TAILQ_LAST(hif->hif_eligible, _eligible);
! 1167: ASSERT(last != NULL);
! 1168: if (last->cl_e <= cl->cl_e) {
! 1169: TAILQ_REMOVE(hif->hif_eligible, cl, cl_ellist);
! 1170: TAILQ_INSERT_TAIL(hif->hif_eligible, cl, cl_ellist);
! 1171: return;
! 1172: }
! 1173:
! 1174: /*
! 1175: * the new position must be between the next entry
! 1176: * and the last entry
! 1177: */
! 1178: while ((p = TAILQ_NEXT(p, cl_ellist)) != NULL) {
! 1179: if (cl->cl_e < p->cl_e) {
! 1180: TAILQ_REMOVE(hif->hif_eligible, cl, cl_ellist);
! 1181: TAILQ_INSERT_BEFORE(p, cl, cl_ellist);
! 1182: return;
! 1183: }
! 1184: }
! 1185: ASSERT(0); /* should not reach here */
! 1186: }
! 1187:
! 1188: /* find the class with the minimum deadline among the eligible classes */
! 1189: struct hfsc_class *
! 1190: ellist_get_mindl(ellist_t *head, u_int64_t cur_time)
! 1191: {
! 1192: struct hfsc_class *p, *cl = NULL;
! 1193:
! 1194: TAILQ_FOREACH(p, head, cl_ellist) {
! 1195: if (p->cl_e > cur_time)
! 1196: break;
! 1197: if (cl == NULL || p->cl_d < cl->cl_d)
! 1198: cl = p;
! 1199: }
! 1200: return (cl);
! 1201: }
! 1202:
! 1203: /*
! 1204: * active children list holds backlogged child classes being sorted
! 1205: * by their virtual time.
! 1206: * each intermediate class has one active children list.
! 1207: */
! 1208: static actlist_t *
! 1209: actlist_alloc(void)
! 1210: {
! 1211: actlist_t *head;
! 1212:
! 1213: MALLOC(head, actlist_t *, sizeof(actlist_t), M_DEVBUF, M_WAITOK);
! 1214: TAILQ_INIT(head);
! 1215: return (head);
! 1216: }
! 1217:
! 1218: static void
! 1219: actlist_destroy(actlist_t *head)
! 1220: {
! 1221: FREE(head, M_DEVBUF);
! 1222: }
! 1223: static void
! 1224: actlist_insert(struct hfsc_class *cl)
! 1225: {
! 1226: struct hfsc_class *p;
! 1227:
! 1228: /* check the last entry first */
! 1229: if ((p = TAILQ_LAST(cl->cl_parent->cl_actc, _active)) == NULL
! 1230: || p->cl_vt <= cl->cl_vt) {
! 1231: TAILQ_INSERT_TAIL(cl->cl_parent->cl_actc, cl, cl_actlist);
! 1232: return;
! 1233: }
! 1234:
! 1235: TAILQ_FOREACH(p, cl->cl_parent->cl_actc, cl_actlist) {
! 1236: if (cl->cl_vt < p->cl_vt) {
! 1237: TAILQ_INSERT_BEFORE(p, cl, cl_actlist);
! 1238: return;
! 1239: }
! 1240: }
! 1241: ASSERT(0); /* should not reach here */
! 1242: }
! 1243:
! 1244: static void
! 1245: actlist_remove(struct hfsc_class *cl)
! 1246: {
! 1247: TAILQ_REMOVE(cl->cl_parent->cl_actc, cl, cl_actlist);
! 1248: }
! 1249:
! 1250: static void
! 1251: actlist_update(struct hfsc_class *cl)
! 1252: {
! 1253: struct hfsc_class *p, *last;
! 1254:
! 1255: /*
! 1256: * the virtual time of a class increases monotonically during its
! 1257: * backlogged period.
! 1258: * if the next entry has a larger virtual time, nothing to do.
! 1259: */
! 1260: p = TAILQ_NEXT(cl, cl_actlist);
! 1261: if (p == NULL || cl->cl_vt < p->cl_vt)
! 1262: return;
! 1263:
! 1264: /* check the last entry */
! 1265: last = TAILQ_LAST(cl->cl_parent->cl_actc, _active);
! 1266: ASSERT(last != NULL);
! 1267: if (last->cl_vt <= cl->cl_vt) {
! 1268: TAILQ_REMOVE(cl->cl_parent->cl_actc, cl, cl_actlist);
! 1269: TAILQ_INSERT_TAIL(cl->cl_parent->cl_actc, cl, cl_actlist);
! 1270: return;
! 1271: }
! 1272:
! 1273: /*
! 1274: * the new position must be between the next entry
! 1275: * and the last entry
! 1276: */
! 1277: while ((p = TAILQ_NEXT(p, cl_actlist)) != NULL) {
! 1278: if (cl->cl_vt < p->cl_vt) {
! 1279: TAILQ_REMOVE(cl->cl_parent->cl_actc, cl, cl_actlist);
! 1280: TAILQ_INSERT_BEFORE(p, cl, cl_actlist);
! 1281: return;
! 1282: }
! 1283: }
! 1284: ASSERT(0); /* should not reach here */
! 1285: }
! 1286:
! 1287: static struct hfsc_class *
! 1288: actlist_firstfit(struct hfsc_class *cl, u_int64_t cur_time)
! 1289: {
! 1290: struct hfsc_class *p;
! 1291:
! 1292: TAILQ_FOREACH(p, cl->cl_actc, cl_actlist) {
! 1293: if (p->cl_f <= cur_time)
! 1294: return (p);
! 1295: }
! 1296: return (NULL);
! 1297: }
! 1298:
! 1299: /*
! 1300: * service curve support functions
! 1301: *
! 1302: * external service curve parameters
! 1303: * m: bits/sec
! 1304: * d: msec
! 1305: * internal service curve parameters
! 1306: * sm: (bytes/tsc_interval) << SM_SHIFT
! 1307: * ism: (tsc_count/byte) << ISM_SHIFT
! 1308: * dx: tsc_count
! 1309: *
! 1310: * SM_SHIFT and ISM_SHIFT are scaled in order to keep effective digits.
! 1311: * we should be able to handle 100K-1Gbps linkspeed with 200Hz-1GHz CPU
! 1312: * speed. SM_SHIFT and ISM_SHIFT are selected to have at least 3 effective
! 1313: * digits in decimal using the following table.
! 1314: *
! 1315: * bits/sec 100Kbps 1Mbps 10Mbps 100Mbps 1Gbps
! 1316: * ----------+-------------------------------------------------------
! 1317: * bytes/nsec 12.5e-6 125e-6 1250e-6 12500e-6 125000e-6
! 1318: * sm(500MHz) 25.0e-6 250e-6 2500e-6 25000e-6 250000e-6
! 1319: * sm(200MHz) 62.5e-6 625e-6 6250e-6 62500e-6 625000e-6
! 1320: *
! 1321: * nsec/byte 80000 8000 800 80 8
! 1322: * ism(500MHz) 40000 4000 400 40 4
! 1323: * ism(200MHz) 16000 1600 160 16 1.6
! 1324: */
! 1325: #define SM_SHIFT 24
! 1326: #define ISM_SHIFT 10
! 1327:
! 1328: #define SM_MASK ((1LL << SM_SHIFT) - 1)
! 1329: #define ISM_MASK ((1LL << ISM_SHIFT) - 1)
! 1330:
! 1331: static __inline u_int64_t
! 1332: seg_x2y(u_int64_t x, u_int64_t sm)
! 1333: {
! 1334: u_int64_t y;
! 1335:
! 1336: /*
! 1337: * compute
! 1338: * y = x * sm >> SM_SHIFT
! 1339: * but divide it for the upper and lower bits to avoid overflow
! 1340: */
! 1341: y = (x >> SM_SHIFT) * sm + (((x & SM_MASK) * sm) >> SM_SHIFT);
! 1342: return (y);
! 1343: }
! 1344:
! 1345: static __inline u_int64_t
! 1346: seg_y2x(u_int64_t y, u_int64_t ism)
! 1347: {
! 1348: u_int64_t x;
! 1349:
! 1350: if (y == 0)
! 1351: x = 0;
! 1352: else if (ism == HT_INFINITY)
! 1353: x = HT_INFINITY;
! 1354: else {
! 1355: x = (y >> ISM_SHIFT) * ism
! 1356: + (((y & ISM_MASK) * ism) >> ISM_SHIFT);
! 1357: }
! 1358: return (x);
! 1359: }
! 1360:
! 1361: static __inline u_int64_t
! 1362: m2sm(u_int m)
! 1363: {
! 1364: u_int64_t sm;
! 1365:
! 1366: sm = ((u_int64_t)m << SM_SHIFT) / 8 / machclk_freq;
! 1367: return (sm);
! 1368: }
! 1369:
! 1370: static __inline u_int64_t
! 1371: m2ism(u_int m)
! 1372: {
! 1373: u_int64_t ism;
! 1374:
! 1375: if (m == 0)
! 1376: ism = HT_INFINITY;
! 1377: else
! 1378: ism = ((u_int64_t)machclk_freq << ISM_SHIFT) * 8 / m;
! 1379: return (ism);
! 1380: }
! 1381:
! 1382: static __inline u_int64_t
! 1383: d2dx(u_int d)
! 1384: {
! 1385: u_int64_t dx;
! 1386:
! 1387: dx = ((u_int64_t)d * machclk_freq) / 1000;
! 1388: return (dx);
! 1389: }
! 1390:
! 1391: static u_int
! 1392: sm2m(u_int64_t sm)
! 1393: {
! 1394: u_int64_t m;
! 1395:
! 1396: m = (sm * 8 * machclk_freq) >> SM_SHIFT;
! 1397: return ((u_int)m);
! 1398: }
! 1399:
! 1400: static u_int
! 1401: dx2d(u_int64_t dx)
! 1402: {
! 1403: u_int64_t d;
! 1404:
! 1405: d = dx * 1000 / machclk_freq;
! 1406: return ((u_int)d);
! 1407: }
! 1408:
! 1409: static void
! 1410: sc2isc(struct service_curve *sc, struct internal_sc *isc)
! 1411: {
! 1412: isc->sm1 = m2sm(sc->m1);
! 1413: isc->ism1 = m2ism(sc->m1);
! 1414: isc->dx = d2dx(sc->d);
! 1415: isc->dy = seg_x2y(isc->dx, isc->sm1);
! 1416: isc->sm2 = m2sm(sc->m2);
! 1417: isc->ism2 = m2ism(sc->m2);
! 1418: }
! 1419:
! 1420: /*
! 1421: * initialize the runtime service curve with the given internal
! 1422: * service curve starting at (x, y).
! 1423: */
! 1424: static void
! 1425: rtsc_init(struct runtime_sc *rtsc, struct internal_sc * isc, u_int64_t x,
! 1426: u_int64_t y)
! 1427: {
! 1428: rtsc->x = x;
! 1429: rtsc->y = y;
! 1430: rtsc->sm1 = isc->sm1;
! 1431: rtsc->ism1 = isc->ism1;
! 1432: rtsc->dx = isc->dx;
! 1433: rtsc->dy = isc->dy;
! 1434: rtsc->sm2 = isc->sm2;
! 1435: rtsc->ism2 = isc->ism2;
! 1436: }
! 1437:
! 1438: /*
! 1439: * calculate the y-projection of the runtime service curve by the
! 1440: * given x-projection value
! 1441: */
! 1442: static u_int64_t
! 1443: rtsc_y2x(struct runtime_sc *rtsc, u_int64_t y)
! 1444: {
! 1445: u_int64_t x;
! 1446:
! 1447: if (y < rtsc->y)
! 1448: x = rtsc->x;
! 1449: else if (y <= rtsc->y + rtsc->dy) {
! 1450: /* x belongs to the 1st segment */
! 1451: if (rtsc->dy == 0)
! 1452: x = rtsc->x + rtsc->dx;
! 1453: else
! 1454: x = rtsc->x + seg_y2x(y - rtsc->y, rtsc->ism1);
! 1455: } else {
! 1456: /* x belongs to the 2nd segment */
! 1457: x = rtsc->x + rtsc->dx
! 1458: + seg_y2x(y - rtsc->y - rtsc->dy, rtsc->ism2);
! 1459: }
! 1460: return (x);
! 1461: }
! 1462:
! 1463: static u_int64_t
! 1464: rtsc_x2y(struct runtime_sc *rtsc, u_int64_t x)
! 1465: {
! 1466: u_int64_t y;
! 1467:
! 1468: if (x <= rtsc->x)
! 1469: y = rtsc->y;
! 1470: else if (x <= rtsc->x + rtsc->dx)
! 1471: /* y belongs to the 1st segment */
! 1472: y = rtsc->y + seg_x2y(x - rtsc->x, rtsc->sm1);
! 1473: else
! 1474: /* y belongs to the 2nd segment */
! 1475: y = rtsc->y + rtsc->dy
! 1476: + seg_x2y(x - rtsc->x - rtsc->dx, rtsc->sm2);
! 1477: return (y);
! 1478: }
! 1479:
! 1480: /*
! 1481: * update the runtime service curve by taking the minimum of the current
! 1482: * runtime service curve and the service curve starting at (x, y).
! 1483: */
! 1484: static void
! 1485: rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u_int64_t x,
! 1486: u_int64_t y)
! 1487: {
! 1488: u_int64_t y1, y2, dx, dy;
! 1489:
! 1490: if (isc->sm1 <= isc->sm2) {
! 1491: /* service curve is convex */
! 1492: y1 = rtsc_x2y(rtsc, x);
! 1493: if (y1 < y)
! 1494: /* the current rtsc is smaller */
! 1495: return;
! 1496: rtsc->x = x;
! 1497: rtsc->y = y;
! 1498: return;
! 1499: }
! 1500:
! 1501: /*
! 1502: * service curve is concave
! 1503: * compute the two y values of the current rtsc
! 1504: * y1: at x
! 1505: * y2: at (x + dx)
! 1506: */
! 1507: y1 = rtsc_x2y(rtsc, x);
! 1508: if (y1 <= y) {
! 1509: /* rtsc is below isc, no change to rtsc */
! 1510: return;
! 1511: }
! 1512:
! 1513: y2 = rtsc_x2y(rtsc, x + isc->dx);
! 1514: if (y2 >= y + isc->dy) {
! 1515: /* rtsc is above isc, replace rtsc by isc */
! 1516: rtsc->x = x;
! 1517: rtsc->y = y;
! 1518: rtsc->dx = isc->dx;
! 1519: rtsc->dy = isc->dy;
! 1520: return;
! 1521: }
! 1522:
! 1523: /*
! 1524: * the two curves intersect
! 1525: * compute the offsets (dx, dy) using the reverse
! 1526: * function of seg_x2y()
! 1527: * seg_x2y(dx, sm1) == seg_x2y(dx, sm2) + (y1 - y)
! 1528: */
! 1529: dx = ((y1 - y) << SM_SHIFT) / (isc->sm1 - isc->sm2);
! 1530: /*
! 1531: * check if (x, y1) belongs to the 1st segment of rtsc.
! 1532: * if so, add the offset.
! 1533: */
! 1534: if (rtsc->x + rtsc->dx > x)
! 1535: dx += rtsc->x + rtsc->dx - x;
! 1536: dy = seg_x2y(dx, isc->sm1);
! 1537:
! 1538: rtsc->x = x;
! 1539: rtsc->y = y;
! 1540: rtsc->dx = dx;
! 1541: rtsc->dy = dy;
! 1542: return;
! 1543: }
! 1544:
! 1545: static void
! 1546: get_class_stats(struct hfsc_classstats *sp, struct hfsc_class *cl)
! 1547: {
! 1548: sp->class_id = cl->cl_id;
! 1549: sp->class_handle = cl->cl_handle;
! 1550:
! 1551: if (cl->cl_rsc != NULL) {
! 1552: sp->rsc.m1 = sm2m(cl->cl_rsc->sm1);
! 1553: sp->rsc.d = dx2d(cl->cl_rsc->dx);
! 1554: sp->rsc.m2 = sm2m(cl->cl_rsc->sm2);
! 1555: } else {
! 1556: sp->rsc.m1 = 0;
! 1557: sp->rsc.d = 0;
! 1558: sp->rsc.m2 = 0;
! 1559: }
! 1560: if (cl->cl_fsc != NULL) {
! 1561: sp->fsc.m1 = sm2m(cl->cl_fsc->sm1);
! 1562: sp->fsc.d = dx2d(cl->cl_fsc->dx);
! 1563: sp->fsc.m2 = sm2m(cl->cl_fsc->sm2);
! 1564: } else {
! 1565: sp->fsc.m1 = 0;
! 1566: sp->fsc.d = 0;
! 1567: sp->fsc.m2 = 0;
! 1568: }
! 1569: if (cl->cl_usc != NULL) {
! 1570: sp->usc.m1 = sm2m(cl->cl_usc->sm1);
! 1571: sp->usc.d = dx2d(cl->cl_usc->dx);
! 1572: sp->usc.m2 = sm2m(cl->cl_usc->sm2);
! 1573: } else {
! 1574: sp->usc.m1 = 0;
! 1575: sp->usc.d = 0;
! 1576: sp->usc.m2 = 0;
! 1577: }
! 1578:
! 1579: sp->total = cl->cl_total;
! 1580: sp->cumul = cl->cl_cumul;
! 1581:
! 1582: sp->d = cl->cl_d;
! 1583: sp->e = cl->cl_e;
! 1584: sp->vt = cl->cl_vt;
! 1585: sp->f = cl->cl_f;
! 1586:
! 1587: sp->initvt = cl->cl_initvt;
! 1588: sp->vtperiod = cl->cl_vtperiod;
! 1589: sp->parentperiod = cl->cl_parentperiod;
! 1590: sp->nactive = cl->cl_nactive;
! 1591: sp->vtoff = cl->cl_vtoff;
! 1592: sp->cvtmax = cl->cl_cvtmax;
! 1593: sp->myf = cl->cl_myf;
! 1594: sp->cfmin = cl->cl_cfmin;
! 1595: sp->cvtmin = cl->cl_cvtmin;
! 1596: sp->myfadj = cl->cl_myfadj;
! 1597: sp->vtadj = cl->cl_vtadj;
! 1598:
! 1599: sp->cur_time = read_machclk();
! 1600: sp->machclk_freq = machclk_freq;
! 1601:
! 1602: sp->qlength = qlen(cl->cl_q);
! 1603: sp->qlimit = qlimit(cl->cl_q);
! 1604: sp->xmit_cnt = cl->cl_stats.xmit_cnt;
! 1605: sp->drop_cnt = cl->cl_stats.drop_cnt;
! 1606: sp->period = cl->cl_stats.period;
! 1607:
! 1608: sp->qtype = qtype(cl->cl_q);
! 1609: #ifdef ALTQ_RED
! 1610: if (q_is_red(cl->cl_q))
! 1611: red_getstats(cl->cl_red, &sp->red[0]);
! 1612: #endif
! 1613: #ifdef ALTQ_RIO
! 1614: if (q_is_rio(cl->cl_q))
! 1615: rio_getstats((rio_t *)cl->cl_red, &sp->red[0]);
! 1616: #endif
! 1617: }
! 1618:
! 1619: /* convert a class handle to the corresponding class pointer */
! 1620: static struct hfsc_class *
! 1621: clh_to_clp(struct hfsc_if *hif, u_int32_t chandle)
! 1622: {
! 1623: int i;
! 1624: struct hfsc_class *cl;
! 1625:
! 1626: if (chandle == 0)
! 1627: return (NULL);
! 1628: /*
! 1629: * first, try the slot corresponding to the lower bits of the handle.
! 1630: * if it does not match, do the linear table search.
! 1631: */
! 1632: i = chandle % HFSC_MAX_CLASSES;
! 1633: if ((cl = hif->hif_class_tbl[i]) != NULL && cl->cl_handle == chandle)
! 1634: return (cl);
! 1635: for (i = 0; i < HFSC_MAX_CLASSES; i++)
! 1636: if ((cl = hif->hif_class_tbl[i]) != NULL &&
! 1637: cl->cl_handle == chandle)
! 1638: return (cl);
! 1639: return (NULL);
! 1640: }
CVSweb