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

Annotation of sys/altq/altq_rmclass.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: altq_rmclass.c,v 1.12 2006/03/04 22:40:15 brad Exp $  */
                      2: /*     $KAME: altq_rmclass.c,v 1.10 2001/02/09 07:20:40 kjc Exp $      */
                      3:
                      4: /*
                      5:  * Copyright (c) 1991-1997 Regents of the University of California.
                      6:  * All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *      This product includes software developed by the Network Research
                     19:  *      Group at Lawrence Berkeley Laboratory.
                     20:  * 4. Neither the name of the University nor of the Laboratory may be used
                     21:  *    to endorse or promote products derived from this software without
                     22:  *    specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  *
                     36:  * LBL code modified by speer@eng.sun.com, May 1977.
                     37:  * For questions and/or comments, please send mail to cbq@ee.lbl.gov
                     38:  */
                     39:
                     40: #include <sys/param.h>
                     41: #include <sys/malloc.h>
                     42: #include <sys/mbuf.h>
                     43: #include <sys/socket.h>
                     44: #include <sys/systm.h>
                     45: #include <sys/errno.h>
                     46: #include <sys/time.h>
                     47:
                     48: #include <net/if.h>
                     49:
                     50: #include <altq/altq.h>
                     51: #include <altq/altq_rmclass.h>
                     52: #include <altq/altq_rmclass_debug.h>
                     53: #include <altq/altq_red.h>
                     54: #include <altq/altq_rio.h>
                     55:
                     56: /*
                     57:  * Local Macros
                     58:  */
                     59:
                     60: #define        reset_cutoff(ifd)       { ifd->cutoff_ = RM_MAXDEPTH; }
                     61:
                     62: /*
                     63:  * Local routines.
                     64:  */
                     65:
                     66: static int      rmc_satisfied(struct rm_class *, struct timeval *);
                     67: static void     rmc_wrr_set_weights(struct rm_ifdat *);
                     68: static void     rmc_depth_compute(struct rm_class *);
                     69: static void     rmc_depth_recompute(rm_class_t *);
                     70:
                     71: static mbuf_t  *_rmc_wrr_dequeue_next(struct rm_ifdat *, int);
                     72: static mbuf_t  *_rmc_prr_dequeue_next(struct rm_ifdat *, int);
                     73:
                     74: static int      _rmc_addq(rm_class_t *, mbuf_t *);
                     75: static void     _rmc_dropq(rm_class_t *);
                     76: static mbuf_t  *_rmc_getq(rm_class_t *);
                     77: static mbuf_t  *_rmc_pollq(rm_class_t *);
                     78:
                     79: static int      rmc_under_limit(struct rm_class *, struct timeval *);
                     80: static void     rmc_tl_satisfied(struct rm_ifdat *, struct timeval *);
                     81: static void     rmc_drop_action(struct rm_class *);
                     82: static void     rmc_restart(struct rm_class *);
                     83: static void     rmc_root_overlimit(struct rm_class *, struct rm_class *);
                     84:
                     85: #define        BORROW_OFFTIME
                     86: /*
                     87:  * BORROW_OFFTIME (experimental):
                     88:  * borrow the offtime of the class borrowing from.
                     89:  * the reason is that when its own offtime is set, the class is unable
                     90:  * to borrow much, especially when cutoff is taking effect.
                     91:  * but when the borrowed class is overloaded (advidle is close to minidle),
                     92:  * use the borrowing class's offtime to avoid overload.
                     93:  */
                     94: #define        ADJUST_CUTOFF
                     95: /*
                     96:  * ADJUST_CUTOFF (experimental):
                     97:  * if no underlimit class is found due to cutoff, increase cutoff and
                     98:  * retry the scheduling loop.
                     99:  * also, don't invoke delay_actions while cutoff is taking effect,
                    100:  * since a sleeping class won't have a chance to be scheduled in the
                    101:  * next loop.
                    102:  *
                    103:  * now heuristics for setting the top-level variable (cutoff_) becomes:
                    104:  *     1. if a packet arrives for a not-overlimit class, set cutoff
                    105:  *        to the depth of the class.
                    106:  *     2. if cutoff is i, and a packet arrives for an overlimit class
                    107:  *        with an underlimit ancestor at a lower level than i (say j),
                    108:  *        then set cutoff to j.
                    109:  *     3. at scheduling a packet, if there is no underlimit class
                    110:  *        due to the current cutoff level, increase cutoff by 1 and
                    111:  *        then try to schedule again.
                    112:  */
                    113:
                    114: /*
                    115:  * rm_class_t *
                    116:  * rmc_newclass(...) - Create a new resource management class at priority
                    117:  * 'pri' on the interface given by 'ifd'.
                    118:  *
                    119:  * nsecPerByte  is the data rate of the interface in nanoseconds/byte.
                    120:  *              E.g., 800 for a 10Mb/s ethernet.  If the class gets less
                    121:  *              than 100% of the bandwidth, this number should be the
                    122:  *              'effective' rate for the class.  Let f be the
                    123:  *              bandwidth fraction allocated to this class, and let
                    124:  *              nsPerByte be the data rate of the output link in
                    125:  *              nanoseconds/byte.  Then nsecPerByte is set to
                    126:  *              nsPerByte / f.  E.g., 1600 (= 800 / .5)
                    127:  *              for a class that gets 50% of an ethernet's bandwidth.
                    128:  *
                    129:  * action       the routine to call when the class is over limit.
                    130:  *
                    131:  * maxq         max allowable queue size for class (in packets).
                    132:  *
                    133:  * parent       parent class pointer.
                    134:  *
                    135:  * borrow       class to borrow from (should be either 'parent' or null).
                    136:  *
                    137:  * maxidle      max value allowed for class 'idle' time estimate (this
                    138:  *              parameter determines how large an initial burst of packets
                    139:  *              can be before overlimit action is invoked.
                    140:  *
                    141:  * offtime      how long 'delay' action will delay when class goes over
                    142:  *              limit (this parameter determines the steady-state burst
                    143:  *              size when a class is running over its limit).
                    144:  *
                    145:  * Maxidle and offtime have to be computed from the following:  If the
                    146:  * average packet size is s, the bandwidth fraction allocated to this
                    147:  * class is f, we want to allow b packet bursts, and the gain of the
                    148:  * averaging filter is g (= 1 - 2^(-RM_FILTER_GAIN)), then:
                    149:  *
                    150:  *   ptime = s * nsPerByte * (1 - f) / f
                    151:  *   maxidle = ptime * (1 - g^b) / g^b
                    152:  *   minidle = -ptime * (1 / (f - 1))
                    153:  *   offtime = ptime * (1 + 1/(1 - g) * (1 - g^(b - 1)) / g^(b - 1)
                    154:  *
                    155:  * Operationally, it's convenient to specify maxidle & offtime in units
                    156:  * independent of the link bandwidth so the maxidle & offtime passed to
                    157:  * this routine are the above values multiplied by 8*f/(1000*nsPerByte).
                    158:  * (The constant factor is a scale factor needed to make the parameters
                    159:  * integers.  This scaling also means that the 'unscaled' values of
                    160:  * maxidle*nsecPerByte/8 and offtime*nsecPerByte/8 will be in microseconds,
                    161:  * not nanoseconds.)  Also note that the 'idle' filter computation keeps
                    162:  * an estimate scaled upward by 2^RM_FILTER_GAIN so the passed value of
                    163:  * maxidle also must be scaled upward by this value.  Thus, the passed
                    164:  * values for maxidle and offtime can be computed as follows:
                    165:  *
                    166:  * maxidle = maxidle * 2^RM_FILTER_GAIN * 8 / (1000 * nsecPerByte)
                    167:  * offtime = offtime * 8 / (1000 * nsecPerByte)
                    168:  *
                    169:  * When USE_HRTIME is employed, then maxidle and offtime become:
                    170:  *     maxidle = maxilde * (8.0 / nsecPerByte);
                    171:  *     offtime = offtime * (8.0 / nsecPerByte);
                    172:  */
                    173:
                    174: struct rm_class *
                    175: rmc_newclass(int pri, struct rm_ifdat *ifd, u_int nsecPerByte,
                    176:     void (*action)(rm_class_t *, rm_class_t *), int maxq,
                    177:     struct rm_class *parent, struct rm_class *borrow, u_int maxidle,
                    178:     int minidle, u_int offtime, int pktsize, int flags)
                    179: {
                    180:        struct rm_class *cl;
                    181:        struct rm_class *peer;
                    182:        int              s;
                    183:
                    184:        if (pri >= RM_MAXPRIO)
                    185:                return (NULL);
                    186: #ifndef ALTQ_RED
                    187:        if (flags & RMCF_RED) {
                    188: #ifdef ALTQ_DEBUG
                    189:                printf("rmc_newclass: RED not configured for CBQ!\n");
                    190: #endif
                    191:                return (NULL);
                    192:        }
                    193: #endif
                    194: #ifndef ALTQ_RIO
                    195:        if (flags & RMCF_RIO) {
                    196: #ifdef ALTQ_DEBUG
                    197:                printf("rmc_newclass: RIO not configured for CBQ!\n");
                    198: #endif
                    199:                return (NULL);
                    200:        }
                    201: #endif
                    202:
                    203:        MALLOC(cl, struct rm_class *, sizeof(struct rm_class),
                    204:               M_DEVBUF, M_WAITOK);
                    205:        if (cl == NULL)
                    206:                return (NULL);
                    207:        bzero(cl, sizeof(struct rm_class));
                    208:        CALLOUT_INIT(&cl->callout_);
                    209:        MALLOC(cl->q_, class_queue_t *, sizeof(class_queue_t),
                    210:               M_DEVBUF, M_WAITOK);
                    211:        if (cl->q_ == NULL) {
                    212:                FREE(cl, M_DEVBUF);
                    213:                return (NULL);
                    214:        }
                    215:        bzero(cl->q_, sizeof(class_queue_t));
                    216:
                    217:        /*
                    218:         * Class initialization.
                    219:         */
                    220:        cl->children_ = NULL;
                    221:        cl->parent_ = parent;
                    222:        cl->borrow_ = borrow;
                    223:        cl->leaf_ = 1;
                    224:        cl->ifdat_ = ifd;
                    225:        cl->pri_ = pri;
                    226:        cl->allotment_ = RM_NS_PER_SEC / nsecPerByte; /* Bytes per sec */
                    227:        cl->depth_ = 0;
                    228:        cl->qthresh_ = 0;
                    229:        cl->ns_per_byte_ = nsecPerByte;
                    230:
                    231:        qlimit(cl->q_) = maxq;
                    232:        qtype(cl->q_) = Q_DROPHEAD;
                    233:        qlen(cl->q_) = 0;
                    234:        cl->flags_ = flags;
                    235:
                    236: #if 1 /* minidle is also scaled in ALTQ */
                    237:        cl->minidle_ = (minidle * (int)nsecPerByte) / 8;
                    238:        if (cl->minidle_ > 0)
                    239:                cl->minidle_ = 0;
                    240: #else
                    241:        cl->minidle_ = minidle;
                    242: #endif
                    243:        cl->maxidle_ = (maxidle * nsecPerByte) / 8;
                    244:        if (cl->maxidle_ == 0)
                    245:                cl->maxidle_ = 1;
                    246: #if 1 /* offtime is also scaled in ALTQ */
                    247:        cl->avgidle_ = cl->maxidle_;
                    248:        cl->offtime_ = ((offtime * nsecPerByte) / 8) >> RM_FILTER_GAIN;
                    249:        if (cl->offtime_ == 0)
                    250:                cl->offtime_ = 1;
                    251: #else
                    252:        cl->avgidle_ = 0;
                    253:        cl->offtime_ = (offtime * nsecPerByte) / 8;
                    254: #endif
                    255:        cl->overlimit = action;
                    256:
                    257: #ifdef ALTQ_RED
                    258:        if (flags & (RMCF_RED|RMCF_RIO)) {
                    259:                int red_flags, red_pkttime;
                    260:
                    261:                red_flags = 0;
                    262:                if (flags & RMCF_ECN)
                    263:                        red_flags |= REDF_ECN;
                    264:                if (flags & RMCF_FLOWVALVE)
                    265:                        red_flags |= REDF_FLOWVALVE;
                    266: #ifdef ALTQ_RIO
                    267:                if (flags & RMCF_CLEARDSCP)
                    268:                        red_flags |= RIOF_CLEARDSCP;
                    269: #endif
                    270:                red_pkttime = nsecPerByte * pktsize  / 1000;
                    271:
                    272:                if (flags & RMCF_RED) {
                    273:                        cl->red_ = red_alloc(0, 0,
                    274:                            qlimit(cl->q_) * 10/100,
                    275:                            qlimit(cl->q_) * 30/100,
                    276:                            red_flags, red_pkttime);
                    277:                        if (cl->red_ != NULL)
                    278:                                qtype(cl->q_) = Q_RED;
                    279:                }
                    280: #ifdef ALTQ_RIO
                    281:                else {
                    282:                        cl->red_ = (red_t *)rio_alloc(0, NULL,
                    283:                                                      red_flags, red_pkttime);
                    284:                        if (cl->red_ != NULL)
                    285:                                qtype(cl->q_) = Q_RIO;
                    286:                }
                    287: #endif
                    288:        }
                    289: #endif /* ALTQ_RED */
                    290:
                    291:        /*
                    292:         * put the class into the class tree
                    293:         */
                    294:        s = splnet();
                    295:        if ((peer = ifd->active_[pri]) != NULL) {
                    296:                /* find the last class at this pri */
                    297:                cl->peer_ = peer;
                    298:                while (peer->peer_ != ifd->active_[pri])
                    299:                        peer = peer->peer_;
                    300:                peer->peer_ = cl;
                    301:        } else {
                    302:                ifd->active_[pri] = cl;
                    303:                cl->peer_ = cl;
                    304:        }
                    305:
                    306:        if (cl->parent_) {
                    307:                cl->next_ = parent->children_;
                    308:                parent->children_ = cl;
                    309:                parent->leaf_ = 0;
                    310:        }
                    311:
                    312:        /*
                    313:         * Compute the depth of this class and its ancestors in the class
                    314:         * hierarchy.
                    315:         */
                    316:        rmc_depth_compute(cl);
                    317:
                    318:        /*
                    319:         * If CBQ's WRR is enabled, then initialize the class WRR state.
                    320:         */
                    321:        if (ifd->wrr_) {
                    322:                ifd->num_[pri]++;
                    323:                ifd->alloc_[pri] += cl->allotment_;
                    324:                rmc_wrr_set_weights(ifd);
                    325:        }
                    326:        splx(s);
                    327:        return (cl);
                    328: }
                    329:
                    330: int
                    331: rmc_modclass(struct rm_class *cl, u_int nsecPerByte, int maxq, u_int maxidle,
                    332:     int minidle, u_int offtime, int pktsize)
                    333: {
                    334:        struct rm_ifdat *ifd;
                    335:        u_int            old_allotment;
                    336:        int              s;
                    337:
                    338:        ifd = cl->ifdat_;
                    339:        old_allotment = cl->allotment_;
                    340:
                    341:        s = splnet();
                    342:        cl->allotment_ = RM_NS_PER_SEC / nsecPerByte; /* Bytes per sec */
                    343:        cl->qthresh_ = 0;
                    344:        cl->ns_per_byte_ = nsecPerByte;
                    345:
                    346:        qlimit(cl->q_) = maxq;
                    347:
                    348: #if 1 /* minidle is also scaled in ALTQ */
                    349:        cl->minidle_ = (minidle * nsecPerByte) / 8;
                    350:        if (cl->minidle_ > 0)
                    351:                cl->minidle_ = 0;
                    352: #else
                    353:        cl->minidle_ = minidle;
                    354: #endif
                    355:        cl->maxidle_ = (maxidle * nsecPerByte) / 8;
                    356:        if (cl->maxidle_ == 0)
                    357:                cl->maxidle_ = 1;
                    358: #if 1 /* offtime is also scaled in ALTQ */
                    359:        cl->avgidle_ = cl->maxidle_;
                    360:        cl->offtime_ = ((offtime * nsecPerByte) / 8) >> RM_FILTER_GAIN;
                    361:        if (cl->offtime_ == 0)
                    362:                cl->offtime_ = 1;
                    363: #else
                    364:        cl->avgidle_ = 0;
                    365:        cl->offtime_ = (offtime * nsecPerByte) / 8;
                    366: #endif
                    367:
                    368:        /*
                    369:         * If CBQ's WRR is enabled, then initialize the class WRR state.
                    370:         */
                    371:        if (ifd->wrr_) {
                    372:                ifd->alloc_[cl->pri_] += cl->allotment_ - old_allotment;
                    373:                rmc_wrr_set_weights(ifd);
                    374:        }
                    375:        splx(s);
                    376:        return (0);
                    377: }
                    378:
                    379: /*
                    380:  * static void
                    381:  * rmc_wrr_set_weights(struct rm_ifdat *ifdat) - This function computes
                    382:  *     the appropriate run robin weights for the CBQ weighted round robin
                    383:  *     algorithm.
                    384:  *
                    385:  *     Returns: NONE
                    386:  */
                    387:
                    388: static void
                    389: rmc_wrr_set_weights(struct rm_ifdat *ifd)
                    390: {
                    391:        int             i;
                    392:        struct rm_class *cl, *clh;
                    393:
                    394:        for (i = 0; i < RM_MAXPRIO; i++) {
                    395:                /*
                    396:                 * This is inverted from that of the simulator to
                    397:                 * maintain precision.
                    398:                 */
                    399:                if (ifd->num_[i] == 0)
                    400:                        ifd->M_[i] = 0;
                    401:                else
                    402:                        ifd->M_[i] = ifd->alloc_[i] /
                    403:                                (ifd->num_[i] * ifd->maxpkt_);
                    404:                /*
                    405:                 * Compute the weighted allotment for each class.
                    406:                 * This takes the expensive div instruction out
                    407:                 * of the main loop for the wrr scheduling path.
                    408:                 * These only get recomputed when a class comes or
                    409:                 * goes.
                    410:                 */
                    411:                if (ifd->active_[i] != NULL) {
                    412:                        clh = cl = ifd->active_[i];
                    413:                        do {
                    414:                                /* safe-guard for slow link or alloc_ == 0 */
                    415:                                if (ifd->M_[i] == 0)
                    416:                                        cl->w_allotment_ = 0;
                    417:                                else
                    418:                                        cl->w_allotment_ = cl->allotment_ /
                    419:                                                ifd->M_[i];
                    420:                                cl = cl->peer_;
                    421:                        } while ((cl != NULL) && (cl != clh));
                    422:                }
                    423:        }
                    424: }
                    425:
                    426: int
                    427: rmc_get_weight(struct rm_ifdat *ifd, int pri)
                    428: {
                    429:        if ((pri >= 0) && (pri < RM_MAXPRIO))
                    430:                return (ifd->M_[pri]);
                    431:        else
                    432:                return (0);
                    433: }
                    434:
                    435: /*
                    436:  * static void
                    437:  * rmc_depth_compute(struct rm_class *cl) - This function computes the
                    438:  *     appropriate depth of class 'cl' and its ancestors.
                    439:  *
                    440:  *     Returns:        NONE
                    441:  */
                    442:
                    443: static void
                    444: rmc_depth_compute(struct rm_class *cl)
                    445: {
                    446:        rm_class_t      *t = cl, *p;
                    447:
                    448:        /*
                    449:         * Recompute the depth for the branch of the tree.
                    450:         */
                    451:        while (t != NULL) {
                    452:                p = t->parent_;
                    453:                if (p && (t->depth_ >= p->depth_)) {
                    454:                        p->depth_ = t->depth_ + 1;
                    455:                        t = p;
                    456:                } else
                    457:                        t = NULL;
                    458:        }
                    459: }
                    460:
                    461: /*
                    462:  * static void
                    463:  * rmc_depth_recompute(struct rm_class *cl) - This function re-computes
                    464:  *     the depth of the tree after a class has been deleted.
                    465:  *
                    466:  *     Returns:        NONE
                    467:  */
                    468:
                    469: static void
                    470: rmc_depth_recompute(rm_class_t *cl)
                    471: {
                    472: #if 1 /* ALTQ */
                    473:        rm_class_t      *p, *t;
                    474:
                    475:        p = cl;
                    476:        while (p != NULL) {
                    477:                if ((t = p->children_) == NULL) {
                    478:                        p->depth_ = 0;
                    479:                } else {
                    480:                        int cdepth = 0;
                    481:
                    482:                        while (t != NULL) {
                    483:                                if (t->depth_ > cdepth)
                    484:                                        cdepth = t->depth_;
                    485:                                t = t->next_;
                    486:                        }
                    487:
                    488:                        if (p->depth_ == cdepth + 1)
                    489:                                /* no change to this parent */
                    490:                                return;
                    491:
                    492:                        p->depth_ = cdepth + 1;
                    493:                }
                    494:
                    495:                p = p->parent_;
                    496:        }
                    497: #else
                    498:        rm_class_t      *t;
                    499:
                    500:        if (cl->depth_ >= 1) {
                    501:                if (cl->children_ == NULL) {
                    502:                        cl->depth_ = 0;
                    503:                } else if ((t = cl->children_) != NULL) {
                    504:                        while (t != NULL) {
                    505:                                if (t->children_ != NULL)
                    506:                                        rmc_depth_recompute(t);
                    507:                                t = t->next_;
                    508:                        }
                    509:                } else
                    510:                        rmc_depth_compute(cl);
                    511:        }
                    512: #endif
                    513: }
                    514:
                    515: /*
                    516:  * void
                    517:  * rmc_delete_class(struct rm_ifdat *ifdat, struct rm_class *cl) - This
                    518:  *     function deletes a class from the link-sharing structure and frees
                    519:  *     all resources associated with the class.
                    520:  *
                    521:  *     Returns: NONE
                    522:  */
                    523:
                    524: void
                    525: rmc_delete_class(struct rm_ifdat *ifd, struct rm_class *cl)
                    526: {
                    527:        struct rm_class *p, *head, *previous;
                    528:        int              s;
                    529:
                    530:        ASSERT(cl->children_ == NULL);
                    531:
                    532:        if (cl->sleeping_)
                    533:                CALLOUT_STOP(&cl->callout_);
                    534:
                    535:        s = splnet();
                    536:        /*
                    537:         * Free packets in the packet queue.
                    538:         * XXX - this may not be a desired behavior.  Packets should be
                    539:         *              re-queued.
                    540:         */
                    541:        rmc_dropall(cl);
                    542:
                    543:        /*
                    544:         * If the class has a parent, then remove the class from the
                    545:         * class from the parent's children chain.
                    546:         */
                    547:        if (cl->parent_ != NULL) {
                    548:                head = cl->parent_->children_;
                    549:                p = previous = head;
                    550:                if (head->next_ == NULL) {
                    551:                        ASSERT(head == cl);
                    552:                        cl->parent_->children_ = NULL;
                    553:                        cl->parent_->leaf_ = 1;
                    554:                } else while (p != NULL) {
                    555:                        if (p == cl) {
                    556:                                if (cl == head)
                    557:                                        cl->parent_->children_ = cl->next_;
                    558:                                else
                    559:                                        previous->next_ = cl->next_;
                    560:                                cl->next_ = NULL;
                    561:                                p = NULL;
                    562:                        } else {
                    563:                                previous = p;
                    564:                                p = p->next_;
                    565:                        }
                    566:                }
                    567:        }
                    568:
                    569:        /*
                    570:         * Delete class from class priority peer list.
                    571:         */
                    572:        if ((p = ifd->active_[cl->pri_]) != NULL) {
                    573:                /*
                    574:                 * If there is more than one member of this priority
                    575:                 * level, then look for class(cl) in the priority level.
                    576:                 */
                    577:                if (p != p->peer_) {
                    578:                        while (p->peer_ != cl)
                    579:                                p = p->peer_;
                    580:                        p->peer_ = cl->peer_;
                    581:
                    582:                        if (ifd->active_[cl->pri_] == cl)
                    583:                                ifd->active_[cl->pri_] = cl->peer_;
                    584:                } else {
                    585:                        ASSERT(p == cl);
                    586:                        ifd->active_[cl->pri_] = NULL;
                    587:                }
                    588:        }
                    589:
                    590:        /*
                    591:         * Recompute the WRR weights.
                    592:         */
                    593:        if (ifd->wrr_) {
                    594:                ifd->alloc_[cl->pri_] -= cl->allotment_;
                    595:                ifd->num_[cl->pri_]--;
                    596:                rmc_wrr_set_weights(ifd);
                    597:        }
                    598:
                    599:        /*
                    600:         * Re-compute the depth of the tree.
                    601:         */
                    602: #if 1 /* ALTQ */
                    603:        rmc_depth_recompute(cl->parent_);
                    604: #else
                    605:        rmc_depth_recompute(ifd->root_);
                    606: #endif
                    607:
                    608:        splx(s);
                    609:
                    610:        /*
                    611:         * Free the class structure.
                    612:         */
                    613:        if (cl->red_ != NULL) {
                    614: #ifdef ALTQ_RIO
                    615:                if (q_is_rio(cl->q_))
                    616:                        rio_destroy((rio_t *)cl->red_);
                    617: #endif
                    618: #ifdef ALTQ_RED
                    619:                if (q_is_red(cl->q_))
                    620:                        red_destroy(cl->red_);
                    621: #endif
                    622:        }
                    623:        FREE(cl->q_, M_DEVBUF);
                    624:        FREE(cl, M_DEVBUF);
                    625: }
                    626:
                    627:
                    628: /*
                    629:  * void
                    630:  * rmc_init(...) - Initialize the resource management data structures
                    631:  *     associated with the output portion of interface 'ifp'.  'ifd' is
                    632:  *     where the structures will be built (for backwards compatibility, the
                    633:  *     structures aren't kept in the ifnet struct).  'nsecPerByte'
                    634:  *     gives the link speed (inverse of bandwidth) in nanoseconds/byte.
                    635:  *     'restart' is the driver-specific routine that the generic 'delay
                    636:  *     until under limit' action will call to restart output.  `maxq'
                    637:  *     is the queue size of the 'link' & 'default' classes.  'maxqueued'
                    638:  *     is the maximum number of packets that the resource management
                    639:  *     code will allow to be queued 'downstream' (this is typically 1).
                    640:  *
                    641:  *     Returns:        NONE
                    642:  */
                    643:
                    644: void
                    645: rmc_init(struct ifaltq *ifq, struct rm_ifdat *ifd, u_int nsecPerByte,
                    646:     void (*restart)(struct ifaltq *), int maxq, int maxqueued, u_int maxidle,
                    647:     int minidle, u_int offtime, int flags)
                    648: {
                    649:        int             i, mtu;
                    650:
                    651:        /*
                    652:         * Initialize the CBQ tracing/debug facility.
                    653:         */
                    654:        CBQTRACEINIT();
                    655:
                    656:        bzero((char *)ifd, sizeof (*ifd));
                    657:        mtu = ifq->altq_ifp->if_mtu;
                    658:        ifd->ifq_ = ifq;
                    659:        ifd->restart = restart;
                    660:        ifd->maxqueued_ = maxqueued;
                    661:        ifd->ns_per_byte_ = nsecPerByte;
                    662:        ifd->maxpkt_ = mtu;
                    663:        ifd->wrr_ = (flags & RMCF_WRR) ? 1 : 0;
                    664:        ifd->efficient_ = (flags & RMCF_EFFICIENT) ? 1 : 0;
                    665: #if 1
                    666:        ifd->maxiftime_ = mtu * nsecPerByte / 1000 * 16;
                    667:        if (mtu * nsecPerByte > 10 * 1000000)
                    668:                ifd->maxiftime_ /= 4;
                    669: #endif
                    670:
                    671:        reset_cutoff(ifd);
                    672:        CBQTRACE(rmc_init, 'INIT', ifd->cutoff_);
                    673:
                    674:        /*
                    675:         * Initialize the CBQ's WRR state.
                    676:         */
                    677:        for (i = 0; i < RM_MAXPRIO; i++) {
                    678:                ifd->alloc_[i] = 0;
                    679:                ifd->M_[i] = 0;
                    680:                ifd->num_[i] = 0;
                    681:                ifd->na_[i] = 0;
                    682:                ifd->active_[i] = NULL;
                    683:        }
                    684:
                    685:        /*
                    686:         * Initialize current packet state.
                    687:         */
                    688:        ifd->qi_ = 0;
                    689:        ifd->qo_ = 0;
                    690:        for (i = 0; i < RM_MAXQUEUED; i++) {
                    691:                ifd->class_[i] = NULL;
                    692:                ifd->curlen_[i] = 0;
                    693:                ifd->borrowed_[i] = NULL;
                    694:        }
                    695:
                    696:        /*
                    697:         * Create the root class of the link-sharing structure.
                    698:         */
                    699:        if ((ifd->root_ = rmc_newclass(0, ifd,
                    700:                                       nsecPerByte,
                    701:                                       rmc_root_overlimit, maxq, 0, 0,
                    702:                                       maxidle, minidle, offtime,
                    703:                                       0, 0)) == NULL) {
                    704:                printf("rmc_init: root class not allocated\n");
                    705:                return ;
                    706:        }
                    707:        ifd->root_->depth_ = 0;
                    708: }
                    709:
                    710: /*
                    711:  * void
                    712:  * rmc_queue_packet(struct rm_class *cl, mbuf_t *m) - Add packet given by
                    713:  *     mbuf 'm' to queue for resource class 'cl'.  This routine is called
                    714:  *     by a driver's if_output routine.  This routine must be called with
                    715:  *     output packet completion interrupts locked out (to avoid racing with
                    716:  *     rmc_dequeue_next).
                    717:  *
                    718:  *     Returns:        0 on successful queueing
                    719:  *                     -1 when packet drop occurs
                    720:  */
                    721: int
                    722: rmc_queue_packet(struct rm_class *cl, mbuf_t *m)
                    723: {
                    724:        struct timeval   now;
                    725:        struct rm_ifdat *ifd = cl->ifdat_;
                    726:        int              cpri = cl->pri_;
                    727:        int              is_empty = qempty(cl->q_);
                    728:
                    729:        RM_GETTIME(now);
                    730:        if (ifd->cutoff_ > 0) {
                    731:                if (TV_LT(&cl->undertime_, &now)) {
                    732:                        if (ifd->cutoff_ > cl->depth_)
                    733:                                ifd->cutoff_ = cl->depth_;
                    734:                        CBQTRACE(rmc_queue_packet, 'ffoc', cl->depth_);
                    735:                }
                    736: #if 1 /* ALTQ */
                    737:                else {
                    738:                        /*
                    739:                         * the class is overlimit. if the class has
                    740:                         * underlimit ancestors, set cutoff to the lowest
                    741:                         * depth among them.
                    742:                         */
                    743:                        struct rm_class *borrow = cl->borrow_;
                    744:
                    745:                        while (borrow != NULL &&
                    746:                               borrow->depth_ < ifd->cutoff_) {
                    747:                                if (TV_LT(&borrow->undertime_, &now)) {
                    748:                                        ifd->cutoff_ = borrow->depth_;
                    749:                                        CBQTRACE(rmc_queue_packet, 'ffob', ifd->cutoff_);
                    750:                                        break;
                    751:                                }
                    752:                                borrow = borrow->borrow_;
                    753:                        }
                    754:                }
                    755: #else /* !ALTQ */
                    756:                else if ((ifd->cutoff_ > 1) && cl->borrow_) {
                    757:                        if (TV_LT(&cl->borrow_->undertime_, &now)) {
                    758:                                ifd->cutoff_ = cl->borrow_->depth_;
                    759:                                CBQTRACE(rmc_queue_packet, 'ffob',
                    760:                                         cl->borrow_->depth_);
                    761:                        }
                    762:                }
                    763: #endif /* !ALTQ */
                    764:        }
                    765:
                    766:        if (_rmc_addq(cl, m) < 0)
                    767:                /* failed */
                    768:                return (-1);
                    769:
                    770:        if (is_empty) {
                    771:                CBQTRACE(rmc_queue_packet, 'ytpe', cl->stats_.handle);
                    772:                ifd->na_[cpri]++;
                    773:        }
                    774:
                    775:        if (qlen(cl->q_) > qlimit(cl->q_)) {
                    776:                /* note: qlimit can be set to 0 or 1 */
                    777:                rmc_drop_action(cl);
                    778:                return (-1);
                    779:        }
                    780:        return (0);
                    781: }
                    782:
                    783: /*
                    784:  * void
                    785:  * rmc_tl_satisfied(struct rm_ifdat *ifd, struct timeval *now) - Check all
                    786:  *     classes to see if they are satisfied.
                    787:  */
                    788:
                    789: static void
                    790: rmc_tl_satisfied(struct rm_ifdat *ifd, struct timeval *now)
                    791: {
                    792:        int              i;
                    793:        rm_class_t      *p, *bp;
                    794:
                    795:        for (i = RM_MAXPRIO - 1; i >= 0; i--) {
                    796:                if ((bp = ifd->active_[i]) != NULL) {
                    797:                        p = bp;
                    798:                        do {
                    799:                                if (!rmc_satisfied(p, now)) {
                    800:                                        ifd->cutoff_ = p->depth_;
                    801:                                        return;
                    802:                                }
                    803:                                p = p->peer_;
                    804:                        } while (p != bp);
                    805:                }
                    806:        }
                    807:
                    808:        reset_cutoff(ifd);
                    809: }
                    810:
                    811: /*
                    812:  * rmc_satisfied - Return 1 of the class is satisfied.  O, otherwise.
                    813:  */
                    814:
                    815: static int
                    816: rmc_satisfied(struct rm_class *cl, struct timeval *now)
                    817: {
                    818:        rm_class_t      *p;
                    819:
                    820:        if (cl == NULL)
                    821:                return (1);
                    822:        if (TV_LT(now, &cl->undertime_))
                    823:                return (1);
                    824:        if (cl->depth_ == 0) {
                    825:                if (!cl->sleeping_ && (qlen(cl->q_) > cl->qthresh_))
                    826:                        return (0);
                    827:                else
                    828:                        return (1);
                    829:        }
                    830:        if (cl->children_ != NULL) {
                    831:                p = cl->children_;
                    832:                while (p != NULL) {
                    833:                        if (!rmc_satisfied(p, now))
                    834:                                return (0);
                    835:                        p = p->next_;
                    836:                }
                    837:        }
                    838:
                    839:        return (1);
                    840: }
                    841:
                    842: /*
                    843:  * Return 1 if class 'cl' is under limit or can borrow from a parent,
                    844:  * 0 if overlimit.  As a side-effect, this routine will invoke the
                    845:  * class overlimit action if the class if overlimit.
                    846:  */
                    847:
                    848: static int
                    849: rmc_under_limit(struct rm_class *cl, struct timeval *now)
                    850: {
                    851:        rm_class_t      *p = cl;
                    852:        rm_class_t      *top;
                    853:        struct rm_ifdat *ifd = cl->ifdat_;
                    854:
                    855:        ifd->borrowed_[ifd->qi_] = NULL;
                    856:        /*
                    857:         * If cl is the root class, then always return that it is
                    858:         * underlimit.  Otherwise, check to see if the class is underlimit.
                    859:         */
                    860:        if (cl->parent_ == NULL)
                    861:                return (1);
                    862:
                    863:        if (cl->sleeping_) {
                    864:                if (TV_LT(now, &cl->undertime_))
                    865:                        return (0);
                    866:
                    867:                CALLOUT_STOP(&cl->callout_);
                    868:                cl->sleeping_ = 0;
                    869:                cl->undertime_.tv_sec = 0;
                    870:                return (1);
                    871:        }
                    872:
                    873:        top = NULL;
                    874:        while (cl->undertime_.tv_sec && TV_LT(now, &cl->undertime_)) {
                    875:                if (((cl = cl->borrow_) == NULL) ||
                    876:                    (cl->depth_ > ifd->cutoff_)) {
                    877: #ifdef ADJUST_CUTOFF
                    878:                        if (cl != NULL)
                    879:                                /* cutoff is taking effect, just
                    880:                                   return false without calling
                    881:                                   the delay action. */
                    882:                                return (0);
                    883: #endif
                    884: #ifdef BORROW_OFFTIME
                    885:                        /*
                    886:                         * check if the class can borrow offtime too.
                    887:                         * borrow offtime from the top of the borrow
                    888:                         * chain if the top class is not overloaded.
                    889:                         */
                    890:                        if (cl != NULL) {
                    891:                                /* cutoff is taking effect, use this class as top. */
                    892:                                top = cl;
                    893:                                CBQTRACE(rmc_under_limit, 'ffou', ifd->cutoff_);
                    894:                        }
                    895:                        if (top != NULL && top->avgidle_ == top->minidle_)
                    896:                                top = NULL;
                    897:                        p->overtime_ = *now;
                    898:                        (p->overlimit)(p, top);
                    899: #else
                    900:                        p->overtime_ = *now;
                    901:                        (p->overlimit)(p, NULL);
                    902: #endif
                    903:                        return (0);
                    904:                }
                    905:                top = cl;
                    906:        }
                    907:
                    908:        if (cl != p)
                    909:                ifd->borrowed_[ifd->qi_] = cl;
                    910:        return (1);
                    911: }
                    912:
                    913: /*
                    914:  * _rmc_wrr_dequeue_next() - This is scheduler for WRR as opposed to
                    915:  *     Packet-by-packet round robin.
                    916:  *
                    917:  * The heart of the weighted round-robin scheduler, which decides which
                    918:  * class next gets to send a packet.  Highest priority first, then
                    919:  * weighted round-robin within priorites.
                    920:  *
                    921:  * Each able-to-send class gets to send until its byte allocation is
                    922:  * exhausted.  Thus, the active pointer is only changed after a class has
                    923:  * exhausted its allocation.
                    924:  *
                    925:  * If the scheduler finds no class that is underlimit or able to borrow,
                    926:  * then the first class found that had a nonzero queue and is allowed to
                    927:  * borrow gets to send.
                    928:  */
                    929:
                    930: static mbuf_t *
                    931: _rmc_wrr_dequeue_next(struct rm_ifdat *ifd, int op)
                    932: {
                    933:        struct rm_class *cl = NULL, *first = NULL;
                    934:        u_int            deficit;
                    935:        int              cpri;
                    936:        mbuf_t          *m;
                    937:        struct timeval   now;
                    938:
                    939:        RM_GETTIME(now);
                    940:
                    941:        /*
                    942:         * if the driver polls the top of the queue and then removes
                    943:         * the polled packet, we must return the same packet.
                    944:         */
                    945:        if (op == ALTDQ_REMOVE && ifd->pollcache_) {
                    946:                cl = ifd->pollcache_;
                    947:                cpri = cl->pri_;
                    948:                if (ifd->efficient_) {
                    949:                        /* check if this class is overlimit */
                    950:                        if (cl->undertime_.tv_sec != 0 &&
                    951:                            rmc_under_limit(cl, &now) == 0)
                    952:                                first = cl;
                    953:                }
                    954:                ifd->pollcache_ = NULL;
                    955:                goto _wrr_out;
                    956:        }
                    957:        else {
                    958:                /* mode == ALTDQ_POLL || pollcache == NULL */
                    959:                ifd->pollcache_ = NULL;
                    960:                ifd->borrowed_[ifd->qi_] = NULL;
                    961:        }
                    962: #ifdef ADJUST_CUTOFF
                    963:  _again:
                    964: #endif
                    965:        for (cpri = RM_MAXPRIO - 1; cpri >= 0; cpri--) {
                    966:                if (ifd->na_[cpri] == 0)
                    967:                        continue;
                    968:                deficit = 0;
                    969:                /*
                    970:                 * Loop through twice for a priority level, if some class
                    971:                 * was unable to send a packet the first round because
                    972:                 * of the weighted round-robin mechanism.
                    973:                 * During the second loop at this level, deficit==2.
                    974:                 * (This second loop is not needed if for every class,
                    975:                 * "M[cl->pri_])" times "cl->allotment" is greater than
                    976:                 * the byte size for the largest packet in the class.)
                    977:                 */
                    978:  _wrr_loop:
                    979:                cl = ifd->active_[cpri];
                    980:                ASSERT(cl != NULL);
                    981:                do {
                    982:                        if ((deficit < 2) && (cl->bytes_alloc_ <= 0))
                    983:                                cl->bytes_alloc_ += cl->w_allotment_;
                    984:                        if (!qempty(cl->q_)) {
                    985:                                if ((cl->undertime_.tv_sec == 0) ||
                    986:                                    rmc_under_limit(cl, &now)) {
                    987:                                        if (cl->bytes_alloc_ > 0 || deficit > 1)
                    988:                                                goto _wrr_out;
                    989:
                    990:                                        /* underlimit but no alloc */
                    991:                                        deficit = 1;
                    992: #if 1
                    993:                                        ifd->borrowed_[ifd->qi_] = NULL;
                    994: #endif
                    995:                                }
                    996:                                else if (first == NULL && cl->borrow_ != NULL)
                    997:                                        first = cl; /* borrowing candidate */
                    998:                        }
                    999:
                   1000:                        cl->bytes_alloc_ = 0;
                   1001:                        cl = cl->peer_;
                   1002:                } while (cl != ifd->active_[cpri]);
                   1003:
                   1004:                if (deficit == 1) {
                   1005:                        /* first loop found an underlimit class with deficit */
                   1006:                        /* Loop on same priority level, with new deficit.  */
                   1007:                        deficit = 2;
                   1008:                        goto _wrr_loop;
                   1009:                }
                   1010:        }
                   1011:
                   1012: #ifdef ADJUST_CUTOFF
                   1013:        /*
                   1014:         * no underlimit class found.  if cutoff is taking effect,
                   1015:         * increase cutoff and try again.
                   1016:         */
                   1017:        if (first != NULL && ifd->cutoff_ < ifd->root_->depth_) {
                   1018:                ifd->cutoff_++;
                   1019:                CBQTRACE(_rmc_wrr_dequeue_next, 'ojda', ifd->cutoff_);
                   1020:                goto _again;
                   1021:        }
                   1022: #endif /* ADJUST_CUTOFF */
                   1023:        /*
                   1024:         * If LINK_EFFICIENCY is turned on, then the first overlimit
                   1025:         * class we encounter will send a packet if all the classes
                   1026:         * of the link-sharing structure are overlimit.
                   1027:         */
                   1028:        reset_cutoff(ifd);
                   1029:        CBQTRACE(_rmc_wrr_dequeue_next, 'otsr', ifd->cutoff_);
                   1030:
                   1031:        if (!ifd->efficient_ || first == NULL)
                   1032:                return (NULL);
                   1033:
                   1034:        cl = first;
                   1035:        cpri = cl->pri_;
                   1036: #if 0  /* too time-consuming for nothing */
                   1037:        if (cl->sleeping_)
                   1038:                CALLOUT_STOP(&cl->callout_);
                   1039:        cl->sleeping_ = 0;
                   1040:        cl->undertime_.tv_sec = 0;
                   1041: #endif
                   1042:        ifd->borrowed_[ifd->qi_] = cl->borrow_;
                   1043:        ifd->cutoff_ = cl->borrow_->depth_;
                   1044:
                   1045:        /*
                   1046:         * Deque the packet and do the book keeping...
                   1047:         */
                   1048:  _wrr_out:
                   1049:        if (op == ALTDQ_REMOVE) {
                   1050:                m = _rmc_getq(cl);
                   1051:                if (m == NULL)
                   1052:                        panic("_rmc_wrr_dequeue_next");
                   1053:                if (qempty(cl->q_))
                   1054:                        ifd->na_[cpri]--;
                   1055:
                   1056:                /*
                   1057:                 * Update class statistics and link data.
                   1058:                 */
                   1059:                if (cl->bytes_alloc_ > 0)
                   1060:                        cl->bytes_alloc_ -= m_pktlen(m);
                   1061:
                   1062:                if ((cl->bytes_alloc_ <= 0) || first == cl)
                   1063:                        ifd->active_[cl->pri_] = cl->peer_;
                   1064:                else
                   1065:                        ifd->active_[cl->pri_] = cl;
                   1066:
                   1067:                ifd->class_[ifd->qi_] = cl;
                   1068:                ifd->curlen_[ifd->qi_] = m_pktlen(m);
                   1069:                ifd->now_[ifd->qi_] = now;
                   1070:                ifd->qi_ = (ifd->qi_ + 1) % ifd->maxqueued_;
                   1071:                ifd->queued_++;
                   1072:        } else {
                   1073:                /* mode == ALTDQ_PPOLL */
                   1074:                m = _rmc_pollq(cl);
                   1075:                ifd->pollcache_ = cl;
                   1076:        }
                   1077:        return (m);
                   1078: }
                   1079:
                   1080: /*
                   1081:  * Dequeue & return next packet from the highest priority class that
                   1082:  * has a packet to send & has enough allocation to send it.  This
                   1083:  * routine is called by a driver whenever it needs a new packet to
                   1084:  * output.
                   1085:  */
                   1086: static mbuf_t *
                   1087: _rmc_prr_dequeue_next(struct rm_ifdat *ifd, int op)
                   1088: {
                   1089:        mbuf_t          *m;
                   1090:        int              cpri;
                   1091:        struct rm_class *cl, *first = NULL;
                   1092:        struct timeval   now;
                   1093:
                   1094:        RM_GETTIME(now);
                   1095:
                   1096:        /*
                   1097:         * if the driver polls the top of the queue and then removes
                   1098:         * the polled packet, we must return the same packet.
                   1099:         */
                   1100:        if (op == ALTDQ_REMOVE && ifd->pollcache_) {
                   1101:                cl = ifd->pollcache_;
                   1102:                cpri = cl->pri_;
                   1103:                ifd->pollcache_ = NULL;
                   1104:                goto _prr_out;
                   1105:        } else {
                   1106:                /* mode == ALTDQ_POLL || pollcache == NULL */
                   1107:                ifd->pollcache_ = NULL;
                   1108:                ifd->borrowed_[ifd->qi_] = NULL;
                   1109:        }
                   1110: #ifdef ADJUST_CUTOFF
                   1111:  _again:
                   1112: #endif
                   1113:        for (cpri = RM_MAXPRIO - 1; cpri >= 0; cpri--) {
                   1114:                if (ifd->na_[cpri] == 0)
                   1115:                        continue;
                   1116:                cl = ifd->active_[cpri];
                   1117:                ASSERT(cl != NULL);
                   1118:                do {
                   1119:                        if (!qempty(cl->q_)) {
                   1120:                                if ((cl->undertime_.tv_sec == 0) ||
                   1121:                                    rmc_under_limit(cl, &now))
                   1122:                                        goto _prr_out;
                   1123:                                if (first == NULL && cl->borrow_ != NULL)
                   1124:                                        first = cl;
                   1125:                        }
                   1126:                        cl = cl->peer_;
                   1127:                } while (cl != ifd->active_[cpri]);
                   1128:        }
                   1129:
                   1130: #ifdef ADJUST_CUTOFF
                   1131:        /*
                   1132:         * no underlimit class found.  if cutoff is taking effect, increase
                   1133:         * cutoff and try again.
                   1134:         */
                   1135:        if (first != NULL && ifd->cutoff_ < ifd->root_->depth_) {
                   1136:                ifd->cutoff_++;
                   1137:                goto _again;
                   1138:        }
                   1139: #endif /* ADJUST_CUTOFF */
                   1140:        /*
                   1141:         * If LINK_EFFICIENCY is turned on, then the first overlimit
                   1142:         * class we encounter will send a packet if all the classes
                   1143:         * of the link-sharing structure are overlimit.
                   1144:         */
                   1145:        reset_cutoff(ifd);
                   1146:        if (!ifd->efficient_ || first == NULL)
                   1147:                return (NULL);
                   1148:
                   1149:        cl = first;
                   1150:        cpri = cl->pri_;
                   1151: #if 0  /* too time-consuming for nothing */
                   1152:        if (cl->sleeping_)
                   1153:                CALLOUT_STOP(&cl->callout_);
                   1154:        cl->sleeping_ = 0;
                   1155:        cl->undertime_.tv_sec = 0;
                   1156: #endif
                   1157:        ifd->borrowed_[ifd->qi_] = cl->borrow_;
                   1158:        ifd->cutoff_ = cl->borrow_->depth_;
                   1159:
                   1160:        /*
                   1161:         * Deque the packet and do the book keeping...
                   1162:         */
                   1163:  _prr_out:
                   1164:        if (op == ALTDQ_REMOVE) {
                   1165:                m = _rmc_getq(cl);
                   1166:                if (m == NULL)
                   1167:                        panic("_rmc_prr_dequeue_next");
                   1168:                if (qempty(cl->q_))
                   1169:                        ifd->na_[cpri]--;
                   1170:
                   1171:                ifd->active_[cpri] = cl->peer_;
                   1172:
                   1173:                ifd->class_[ifd->qi_] = cl;
                   1174:                ifd->curlen_[ifd->qi_] = m_pktlen(m);
                   1175:                ifd->now_[ifd->qi_] = now;
                   1176:                ifd->qi_ = (ifd->qi_ + 1) % ifd->maxqueued_;
                   1177:                ifd->queued_++;
                   1178:        } else {
                   1179:                /* mode == ALTDQ_POLL */
                   1180:                m = _rmc_pollq(cl);
                   1181:                ifd->pollcache_ = cl;
                   1182:        }
                   1183:        return (m);
                   1184: }
                   1185:
                   1186: /*
                   1187:  * mbuf_t *
                   1188:  * rmc_dequeue_next(struct rm_ifdat *ifd, struct timeval *now) - this function
                   1189:  *     is invoked by the packet driver to get the next packet to be
                   1190:  *     dequeued and output on the link.  If WRR is enabled, then the
                   1191:  *     WRR dequeue next routine will determine the next packet to sent.
                   1192:  *     Otherwise, packet-by-packet round robin is invoked.
                   1193:  *
                   1194:  *     Returns:        NULL, if a packet is not available or if all
                   1195:  *                     classes are overlimit.
                   1196:  *
                   1197:  *                     Otherwise, Pointer to the next packet.
                   1198:  */
                   1199:
                   1200: mbuf_t *
                   1201: rmc_dequeue_next(struct rm_ifdat *ifd, int mode)
                   1202: {
                   1203:        if (ifd->queued_ >= ifd->maxqueued_)
                   1204:                return (NULL);
                   1205:        else if (ifd->wrr_)
                   1206:                return (_rmc_wrr_dequeue_next(ifd, mode));
                   1207:        else
                   1208:                return (_rmc_prr_dequeue_next(ifd, mode));
                   1209: }
                   1210:
                   1211: /*
                   1212:  * Update the utilization estimate for the packet that just completed.
                   1213:  * The packet's class & the parent(s) of that class all get their
                   1214:  * estimators updated.  This routine is called by the driver's output-
                   1215:  * packet-completion interrupt service routine.
                   1216:  */
                   1217:
                   1218: /*
                   1219:  * a macro to approximate "divide by 1000" that gives 0.000999,
                   1220:  * if a value has enough effective digits.
                   1221:  * (on pentium, mul takes 9 cycles but div takes 46!)
                   1222:  */
                   1223: #define        NSEC_TO_USEC(t) (((t) >> 10) + ((t) >> 16) + ((t) >> 17))
                   1224: void
                   1225: rmc_update_class_util(struct rm_ifdat *ifd)
                   1226: {
                   1227:        int              idle, avgidle, pktlen;
                   1228:        int              pkt_time, tidle;
                   1229:        rm_class_t      *cl, *borrowed;
                   1230:        rm_class_t      *borrows;
                   1231:        struct timeval  *nowp;
                   1232:
                   1233:        /*
                   1234:         * Get the most recent completed class.
                   1235:         */
                   1236:        if ((cl = ifd->class_[ifd->qo_]) == NULL)
                   1237:                return;
                   1238:
                   1239:        pktlen = ifd->curlen_[ifd->qo_];
                   1240:        borrowed = ifd->borrowed_[ifd->qo_];
                   1241:        borrows = borrowed;
                   1242:
                   1243:        PKTCNTR_ADD(&cl->stats_.xmit_cnt, pktlen);
                   1244:
                   1245:        /*
                   1246:         * Run estimator on class and its ancestors.
                   1247:         */
                   1248:        /*
                   1249:         * rm_update_class_util is designed to be called when the
                   1250:         * transfer is completed from a xmit complete interrupt,
                   1251:         * but most drivers don't implement an upcall for that.
                   1252:         * so, just use estimated completion time.
                   1253:         * as a result, ifd->qi_ and ifd->qo_ are always synced.
                   1254:         */
                   1255:        nowp = &ifd->now_[ifd->qo_];
                   1256:        /* get pkt_time (for link) in usec */
                   1257: #if 1  /* use approximation */
                   1258:        pkt_time = ifd->curlen_[ifd->qo_] * ifd->ns_per_byte_;
                   1259:        pkt_time = NSEC_TO_USEC(pkt_time);
                   1260: #else
                   1261:        pkt_time = ifd->curlen_[ifd->qo_] * ifd->ns_per_byte_ / 1000;
                   1262: #endif
                   1263: #if 1 /* ALTQ4PPP */
                   1264:        if (TV_LT(nowp, &ifd->ifnow_)) {
                   1265:                int iftime;
                   1266:
                   1267:                /*
                   1268:                 * make sure the estimated completion time does not go
                   1269:                 * too far.  it can happen when the link layer supports
                   1270:                 * data compression or the interface speed is set to
                   1271:                 * a much lower value.
                   1272:                 */
                   1273:                TV_DELTA(&ifd->ifnow_, nowp, iftime);
                   1274:                if (iftime+pkt_time < ifd->maxiftime_) {
                   1275:                        TV_ADD_DELTA(&ifd->ifnow_, pkt_time, &ifd->ifnow_);
                   1276:                } else {
                   1277:                        TV_ADD_DELTA(nowp, ifd->maxiftime_, &ifd->ifnow_);
                   1278:                }
                   1279:        } else {
                   1280:                TV_ADD_DELTA(nowp, pkt_time, &ifd->ifnow_);
                   1281:        }
                   1282: #else
                   1283:        if (TV_LT(nowp, &ifd->ifnow_)) {
                   1284:                TV_ADD_DELTA(&ifd->ifnow_, pkt_time, &ifd->ifnow_);
                   1285:        } else {
                   1286:                TV_ADD_DELTA(nowp, pkt_time, &ifd->ifnow_);
                   1287:        }
                   1288: #endif
                   1289:
                   1290:        while (cl != NULL) {
                   1291:                TV_DELTA(&ifd->ifnow_, &cl->last_, idle);
                   1292:                if (idle >= 2000000)
                   1293:                        /*
                   1294:                         * this class is idle enough, reset avgidle.
                   1295:                         * (TV_DELTA returns 2000000 us when delta is large.)
                   1296:                         */
                   1297:                        cl->avgidle_ = cl->maxidle_;
                   1298:
                   1299:                /* get pkt_time (for class) in usec */
                   1300: #if 1  /* use approximation */
                   1301:                pkt_time = pktlen * cl->ns_per_byte_;
                   1302:                pkt_time = NSEC_TO_USEC(pkt_time);
                   1303: #else
                   1304:                pkt_time = pktlen * cl->ns_per_byte_ / 1000;
                   1305: #endif
                   1306:                idle -= pkt_time;
                   1307:
                   1308:                avgidle = cl->avgidle_;
                   1309:                avgidle += idle - (avgidle >> RM_FILTER_GAIN);
                   1310:                cl->avgidle_ = avgidle;
                   1311:
                   1312:                /* Are we overlimit ? */
                   1313:                if (avgidle <= 0) {
                   1314:                        CBQTRACE(rmc_update_class_util, 'milo', cl->stats_.handle);
                   1315: #if 1 /* ALTQ */
                   1316:                        /*
                   1317:                         * need some lower bound for avgidle, otherwise
                   1318:                         * a borrowing class gets unbounded penalty.
                   1319:                         */
                   1320:                        if (avgidle < cl->minidle_)
                   1321:                                avgidle = cl->avgidle_ = cl->minidle_;
                   1322: #endif
                   1323:                        /* set next idle to make avgidle 0 */
                   1324:                        tidle = pkt_time +
                   1325:                                (((1 - RM_POWER) * avgidle) >> RM_FILTER_GAIN);
                   1326:                        TV_ADD_DELTA(nowp, tidle, &cl->undertime_);
                   1327:                        ++cl->stats_.over;
                   1328:                } else {
                   1329:                        cl->avgidle_ =
                   1330:                            (avgidle > cl->maxidle_) ? cl->maxidle_ : avgidle;
                   1331:                        cl->undertime_.tv_sec = 0;
                   1332:                        if (cl->sleeping_) {
                   1333:                                CALLOUT_STOP(&cl->callout_);
                   1334:                                cl->sleeping_ = 0;
                   1335:                        }
                   1336:                }
                   1337:
                   1338:                if (borrows != NULL) {
                   1339:                        if (borrows != cl)
                   1340:                                ++cl->stats_.borrows;
                   1341:                        else
                   1342:                                borrows = NULL;
                   1343:                }
                   1344:                cl->last_ = ifd->ifnow_;
                   1345:                cl->last_pkttime_ = pkt_time;
                   1346:
                   1347: #if 1
                   1348:                if (cl->parent_ == NULL) {
                   1349:                        /* take stats of root class */
                   1350:                        PKTCNTR_ADD(&cl->stats_.xmit_cnt, pktlen);
                   1351:                }
                   1352: #endif
                   1353:
                   1354:                cl = cl->parent_;
                   1355:        }
                   1356:
                   1357:        /*
                   1358:         * Check to see if cutoff needs to set to a new level.
                   1359:         */
                   1360:        cl = ifd->class_[ifd->qo_];
                   1361:        if (borrowed && (ifd->cutoff_ >= borrowed->depth_)) {
                   1362: #if 1 /* ALTQ */
                   1363:                if ((qlen(cl->q_) <= 0) || TV_LT(nowp, &borrowed->undertime_)) {
                   1364:                        rmc_tl_satisfied(ifd, nowp);
                   1365:                        CBQTRACE(rmc_update_class_util, 'broe', ifd->cutoff_);
                   1366:                } else {
                   1367:                        ifd->cutoff_ = borrowed->depth_;
                   1368:                        CBQTRACE(rmc_update_class_util, 'ffob', borrowed->depth_);
                   1369:                }
                   1370: #else /* !ALTQ */
                   1371:                if ((qlen(cl->q_) <= 1) || TV_LT(&now, &borrowed->undertime_)) {
                   1372:                        reset_cutoff(ifd);
                   1373: #ifdef notdef
                   1374:                        rmc_tl_satisfied(ifd, &now);
                   1375: #endif
                   1376:                        CBQTRACE(rmc_update_class_util, 'broe', ifd->cutoff_);
                   1377:                } else {
                   1378:                        ifd->cutoff_ = borrowed->depth_;
                   1379:                        CBQTRACE(rmc_update_class_util, 'ffob', borrowed->depth_);
                   1380:                }
                   1381: #endif /* !ALTQ */
                   1382:        }
                   1383:
                   1384:        /*
                   1385:         * Release class slot
                   1386:         */
                   1387:        ifd->borrowed_[ifd->qo_] = NULL;
                   1388:        ifd->class_[ifd->qo_] = NULL;
                   1389:        ifd->qo_ = (ifd->qo_ + 1) % ifd->maxqueued_;
                   1390:        ifd->queued_--;
                   1391: }
                   1392:
                   1393: /*
                   1394:  * void
                   1395:  * rmc_drop_action(struct rm_class *cl) - Generic (not protocol-specific)
                   1396:  *     over-limit action routines.  These get invoked by rmc_under_limit()
                   1397:  *     if a class with packets to send if over its bandwidth limit & can't
                   1398:  *     borrow from a parent class.
                   1399:  *
                   1400:  *     Returns: NONE
                   1401:  */
                   1402:
                   1403: static void
                   1404: rmc_drop_action(struct rm_class *cl)
                   1405: {
                   1406:        struct rm_ifdat *ifd = cl->ifdat_;
                   1407:
                   1408:        ASSERT(qlen(cl->q_) > 0);
                   1409:        _rmc_dropq(cl);
                   1410:        if (qempty(cl->q_))
                   1411:                ifd->na_[cl->pri_]--;
                   1412: }
                   1413:
                   1414: void rmc_dropall(struct rm_class *cl)
                   1415: {
                   1416:        struct rm_ifdat *ifd = cl->ifdat_;
                   1417:
                   1418:        if (!qempty(cl->q_)) {
                   1419:                _flushq(cl->q_);
                   1420:
                   1421:                ifd->na_[cl->pri_]--;
                   1422:        }
                   1423: }
                   1424:
                   1425: /*
                   1426:  * void
                   1427:  * rmc_delay_action(struct rm_class *cl) - This function is the generic CBQ
                   1428:  *     delay action routine.  It is invoked via rmc_under_limit when the
                   1429:  *     packet is discovered to be overlimit.
                   1430:  *
                   1431:  *     If the delay action is result of borrow class being overlimit, then
                   1432:  *     delay for the offtime of the borrowing class that is overlimit.
                   1433:  *
                   1434:  *     Returns: NONE
                   1435:  */
                   1436:
                   1437: void
                   1438: rmc_delay_action(struct rm_class *cl, struct rm_class *borrow)
                   1439: {
                   1440:        int     delay, t, extradelay;
                   1441:
                   1442:        cl->stats_.overactions++;
                   1443:        TV_DELTA(&cl->undertime_, &cl->overtime_, delay);
                   1444: #ifndef BORROW_OFFTIME
                   1445:        delay += cl->offtime_;
                   1446: #endif
                   1447:
                   1448:        if (!cl->sleeping_) {
                   1449:                CBQTRACE(rmc_delay_action, 'yled', cl->stats_.handle);
                   1450: #ifdef BORROW_OFFTIME
                   1451:                if (borrow != NULL)
                   1452:                        extradelay = borrow->offtime_;
                   1453:                else
                   1454: #endif
                   1455:                        extradelay = cl->offtime_;
                   1456:
                   1457: #ifdef ALTQ
                   1458:                /*
                   1459:                 * XXX recalculate suspend time:
                   1460:                 * current undertime is (tidle + pkt_time) calculated
                   1461:                 * from the last transmission.
                   1462:                 *      tidle: time required to bring avgidle back to 0
                   1463:                 *      pkt_time: target waiting time for this class
                   1464:                 * we need to replace pkt_time by offtime
                   1465:                 */
                   1466:                extradelay -= cl->last_pkttime_;
                   1467: #endif
                   1468:                if (extradelay > 0) {
                   1469:                        TV_ADD_DELTA(&cl->undertime_, extradelay, &cl->undertime_);
                   1470:                        delay += extradelay;
                   1471:                }
                   1472:
                   1473:                cl->sleeping_ = 1;
                   1474:                cl->stats_.delays++;
                   1475:
                   1476:                /*
                   1477:                 * Since packets are phased randomly with respect to the
                   1478:                 * clock, 1 tick (the next clock tick) can be an arbitrarily
                   1479:                 * short time so we have to wait for at least two ticks.
                   1480:                 * NOTE:  If there's no other traffic, we need the timer as
                   1481:                 * a 'backstop' to restart this class.
                   1482:                 */
                   1483:                if (delay > tick * 2) {
                   1484: #ifdef __FreeBSD__
                   1485:                        /* FreeBSD rounds up the tick */
                   1486:                        t = hzto(&cl->undertime_);
                   1487: #else
                   1488:                        /* other BSDs round down the tick */
                   1489:                        t = hzto(&cl->undertime_) + 1;
                   1490: #endif
                   1491:                } else
                   1492:                        t = 2;
                   1493:                CALLOUT_RESET(&cl->callout_, t,
                   1494:                              (timeout_t *)rmc_restart, (caddr_t)cl);
                   1495:        }
                   1496: }
                   1497:
                   1498: /*
                   1499:  * void
                   1500:  * rmc_restart() - is just a helper routine for rmc_delay_action -- it is
                   1501:  *     called by the system timer code & is responsible checking if the
                   1502:  *     class is still sleeping (it might have been restarted as a side
                   1503:  *     effect of the queue scan on a packet arrival) and, if so, restarting
                   1504:  *     output for the class.  Inspecting the class state & restarting output
                   1505:  *     require locking the class structure.  In general the driver is
                   1506:  *     responsible for locking but this is the only routine that is not
                   1507:  *     called directly or indirectly from the interface driver so it has
                   1508:  *     know about system locking conventions.  Under bsd, locking is done
                   1509:  *     by raising IPL to splnet so that's what's implemented here.  On a
                   1510:  *     different system this would probably need to be changed.
                   1511:  *
                   1512:  *     Returns:        NONE
                   1513:  */
                   1514:
                   1515: static void
                   1516: rmc_restart(struct rm_class *cl)
                   1517: {
                   1518:        struct rm_ifdat *ifd = cl->ifdat_;
                   1519:        int              s;
                   1520:
                   1521:        s = splnet();
                   1522:        if (cl->sleeping_) {
                   1523:                cl->sleeping_ = 0;
                   1524:                cl->undertime_.tv_sec = 0;
                   1525:
                   1526:                if (ifd->queued_ < ifd->maxqueued_ && ifd->restart != NULL) {
                   1527:                        CBQTRACE(rmc_restart, 'trts', cl->stats_.handle);
                   1528:                        (ifd->restart)(ifd->ifq_);
                   1529:                }
                   1530:        }
                   1531:        splx(s);
                   1532: }
                   1533:
                   1534: /*
                   1535:  * void
                   1536:  * rmc_root_overlimit(struct rm_class *cl) - This the generic overlimit
                   1537:  *     handling routine for the root class of the link sharing structure.
                   1538:  *
                   1539:  *     Returns: NONE
                   1540:  */
                   1541:
                   1542: static void
                   1543: rmc_root_overlimit(struct rm_class *cl, struct rm_class *borrow)
                   1544: {
                   1545:     panic("rmc_root_overlimit");
                   1546: }
                   1547:
                   1548: /*
                   1549:  * Packet Queue handling routines.  Eventually, this is to localize the
                   1550:  *     effects on the code whether queues are red queues or droptail
                   1551:  *     queues.
                   1552:  */
                   1553:
                   1554: static int
                   1555: _rmc_addq(rm_class_t *cl, mbuf_t *m)
                   1556: {
                   1557: #ifdef ALTQ_RIO
                   1558:        if (q_is_rio(cl->q_))
                   1559:                return rio_addq((rio_t *)cl->red_, cl->q_, m, cl->pktattr_);
                   1560: #endif
                   1561: #ifdef ALTQ_RED
                   1562:        if (q_is_red(cl->q_))
                   1563:                return red_addq(cl->red_, cl->q_, m, cl->pktattr_);
                   1564: #endif /* ALTQ_RED */
                   1565:
                   1566:        if (cl->flags_ & RMCF_CLEARDSCP)
                   1567:                write_dsfield(m, cl->pktattr_, 0);
                   1568:
                   1569:        _addq(cl->q_, m);
                   1570:        return (0);
                   1571: }
                   1572:
                   1573: /* note: _rmc_dropq is not called for red */
                   1574: static void
                   1575: _rmc_dropq(rm_class_t *cl)
                   1576: {
                   1577:        mbuf_t  *m;
                   1578:
                   1579:        if ((m = _getq(cl->q_)) != NULL)
                   1580:                m_freem(m);
                   1581: }
                   1582:
                   1583: static mbuf_t *
                   1584: _rmc_getq(rm_class_t *cl)
                   1585: {
                   1586: #ifdef ALTQ_RIO
                   1587:        if (q_is_rio(cl->q_))
                   1588:                return rio_getq((rio_t *)cl->red_, cl->q_);
                   1589: #endif
                   1590: #ifdef ALTQ_RED
                   1591:        if (q_is_red(cl->q_))
                   1592:                return red_getq(cl->red_, cl->q_);
                   1593: #endif
                   1594:        return _getq(cl->q_);
                   1595: }
                   1596:
                   1597: static mbuf_t *
                   1598: _rmc_pollq(rm_class_t *cl)
                   1599: {
                   1600:        return qhead(cl->q_);
                   1601: }
                   1602:
                   1603: #ifdef CBQ_TRACE
                   1604:
                   1605: struct cbqtrace                 cbqtrace_buffer[NCBQTRACE+1];
                   1606: struct cbqtrace                *cbqtrace_ptr = NULL;
                   1607: int                     cbqtrace_count;
                   1608:
                   1609: /*
                   1610:  * DDB hook to trace cbq events:
                   1611:  *  the last 1024 events are held in a circular buffer.
                   1612:  *  use "call cbqtrace_dump(N)" to display 20 events from Nth event.
                   1613:  */
                   1614: void cbqtrace_dump(int);
                   1615: static char *rmc_funcname(void *);
                   1616:
                   1617: static struct rmc_funcs {
                   1618:        void    *func;
                   1619:        char    *name;
                   1620: } rmc_funcs[] =
                   1621: {
                   1622:        rmc_init,               "rmc_init",
                   1623:        rmc_queue_packet,       "rmc_queue_packet",
                   1624:        rmc_under_limit,        "rmc_under_limit",
                   1625:        rmc_update_class_util,  "rmc_update_class_util",
                   1626:        rmc_delay_action,       "rmc_delay_action",
                   1627:        rmc_restart,            "rmc_restart",
                   1628:        _rmc_wrr_dequeue_next,  "_rmc_wrr_dequeue_next",
                   1629:        NULL,                   NULL
                   1630: };
                   1631:
                   1632: static char *rmc_funcname(void *func)
                   1633: {
                   1634:        struct rmc_funcs *fp;
                   1635:
                   1636:        for (fp = rmc_funcs; fp->func != NULL; fp++)
                   1637:                if (fp->func == func)
                   1638:                        return (fp->name);
                   1639:        return ("unknown");
                   1640: }
                   1641:
                   1642: void cbqtrace_dump(int counter)
                   1643: {
                   1644:        int      i, *p;
                   1645:        char    *cp;
                   1646:
                   1647:        counter = counter % NCBQTRACE;
                   1648:        p = (int *)&cbqtrace_buffer[counter];
                   1649:
                   1650:        for (i=0; i<20; i++) {
                   1651:                printf("[0x%x] ", *p++);
                   1652:                printf("%s: ", rmc_funcname((void *)*p++));
                   1653:                cp = (char *)p++;
                   1654:                printf("%c%c%c%c: ", cp[0], cp[1], cp[2], cp[3]);
                   1655:                printf("%d\n",*p++);
                   1656:
                   1657:                if (p >= (int *)&cbqtrace_buffer[NCBQTRACE])
                   1658:                        p = (int *)cbqtrace_buffer;
                   1659:        }
                   1660: }
                   1661: #endif /* CBQ_TRACE */
                   1662:
                   1663: #if defined(ALTQ_CBQ) || defined(ALTQ_RED) || defined(ALTQ_RIO) || defined(ALTQ_HFSC) || defined(ALTQ_PRIQ)
                   1664: #if !defined(__GNUC__) || defined(ALTQ_DEBUG)
                   1665:
                   1666: void
                   1667: _addq(class_queue_t *q, mbuf_t *m)
                   1668: {
                   1669:         mbuf_t *m0;
                   1670:
                   1671:        if ((m0 = qtail(q)) != NULL)
                   1672:                m->m_nextpkt = m0->m_nextpkt;
                   1673:        else
                   1674:                m0 = m;
                   1675:        m0->m_nextpkt = m;
                   1676:        qtail(q) = m;
                   1677:        qlen(q)++;
                   1678: }
                   1679:
                   1680: mbuf_t *
                   1681: _getq(class_queue_t *q)
                   1682: {
                   1683:        mbuf_t  *m, *m0;
                   1684:
                   1685:        if ((m = qtail(q)) == NULL)
                   1686:                return (NULL);
                   1687:        if ((m0 = m->m_nextpkt) != m)
                   1688:                m->m_nextpkt = m0->m_nextpkt;
                   1689:        else {
                   1690:                ASSERT(qlen(q) == 1);
                   1691:                qtail(q) = NULL;
                   1692:        }
                   1693:        qlen(q)--;
                   1694:        m0->m_nextpkt = NULL;
                   1695:        return (m0);
                   1696: }
                   1697:
                   1698: /* drop a packet at the tail of the queue */
                   1699: mbuf_t *
                   1700: _getq_tail(class_queue_t *q)
                   1701: {
                   1702:        mbuf_t  *m, *m0, *prev;
                   1703:
                   1704:        if ((m = m0 = qtail(q)) == NULL)
                   1705:                return NULL;
                   1706:        do {
                   1707:                prev = m0;
                   1708:                m0 = m0->m_nextpkt;
                   1709:        } while (m0 != m);
                   1710:        prev->m_nextpkt = m->m_nextpkt;
                   1711:        if (prev == m)  {
                   1712:                ASSERT(qlen(q) == 1);
                   1713:                qtail(q) = NULL;
                   1714:        } else
                   1715:                qtail(q) = prev;
                   1716:        qlen(q)--;
                   1717:        m->m_nextpkt = NULL;
                   1718:        return (m);
                   1719: }
                   1720:
                   1721: /* randomly select a packet in the queue */
                   1722: mbuf_t *
                   1723: _getq_random(class_queue_t *q)
                   1724: {
                   1725:        struct mbuf     *m;
                   1726:        int              i, n;
                   1727:
                   1728:        if ((m = qtail(q)) == NULL)
                   1729:                return NULL;
                   1730:        if (m->m_nextpkt == m) {
                   1731:                ASSERT(qlen(q) == 1);
                   1732:                qtail(q) = NULL;
                   1733:        } else {
                   1734:                struct mbuf *prev = NULL;
                   1735:
                   1736:                n = random() % qlen(q) + 1;
                   1737:                for (i = 0; i < n; i++) {
                   1738:                        prev = m;
                   1739:                        m = m->m_nextpkt;
                   1740:                }
                   1741:                prev->m_nextpkt = m->m_nextpkt;
                   1742:                if (m == qtail(q))
                   1743:                        qtail(q) = prev;
                   1744:        }
                   1745:        qlen(q)--;
                   1746:        m->m_nextpkt = NULL;
                   1747:        return (m);
                   1748: }
                   1749:
                   1750: void
                   1751: _removeq(class_queue_t *q, mbuf_t *m)
                   1752: {
                   1753:        mbuf_t  *m0, *prev;
                   1754:
                   1755:        m0 = qtail(q);
                   1756:        do {
                   1757:                prev = m0;
                   1758:                m0 = m0->m_nextpkt;
                   1759:        } while (m0 != m);
                   1760:        prev->m_nextpkt = m->m_nextpkt;
                   1761:        if (prev == m)
                   1762:                qtail(q) = NULL;
                   1763:        else if (qtail(q) == m)
                   1764:                qtail(q) = prev;
                   1765:        qlen(q)--;
                   1766: }
                   1767:
                   1768: void
                   1769: _flushq(class_queue_t *q)
                   1770: {
                   1771:        mbuf_t *m;
                   1772:
                   1773:        while ((m = _getq(q)) != NULL)
                   1774:                m_freem(m);
                   1775:        ASSERT(qlen(q) == 0);
                   1776: }
                   1777:
                   1778: #endif /* !__GNUC__ || ALTQ_DEBUG */
                   1779: #endif /* ALTQ_CBQ || ALTQ_RED || ALTQ_RIO || ALTQ_HFSC || ALTQ_PRIQ */

CVSweb