[BACK]Return to altq_hfsc.c CVS log [TXT][DIR] Up to [local] / sys / altq

Annotation of sys/altq/altq_hfsc.c, Revision 1.1.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