]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/pktsched/pktsched_rmclass.c
xnu-4570.1.46.tar.gz
[apple/xnu.git] / bsd / net / pktsched / pktsched_rmclass.c
diff --git a/bsd/net/pktsched/pktsched_rmclass.c b/bsd/net/pktsched/pktsched_rmclass.c
deleted file mode 100644 (file)
index 89b98e1..0000000
+++ /dev/null
@@ -1,1852 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. The rights granted to you under the License
- * may not be used to create, or enable the creation or redistribution of,
- * unlawful or unlicensed copies of an Apple operating system, or to
- * circumvent, violate, or enable the circumvention or violation of, any
- * terms of an Apple operating system software license agreement.
- *
- * Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
- */
-
-/*     $OpenBSD: altq_rmclass.c,v 1.13 2007/09/13 20:40:02 chl Exp $   */
-/*     $KAME: altq_rmclass.c,v 1.10 2001/02/09 07:20:40 kjc Exp $      */
-
-/*
- * Copyright (c) 1991-1997 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *      This product includes software developed by the Network Research
- *      Group at Lawrence Berkeley Laboratory.
- * 4. Neither the name of the University nor of the Laboratory may be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * LBL code modified by speer@eng.sun.com, May 1977.
- * For questions and/or comments, please send mail to cbq@ee.lbl.gov
- */
-
-#include <sys/cdefs.h>
-
-#ident "@(#)rm_class.c  1.48     97/12/05 SMI"
-
-#if PKTSCHED_CBQ
-
-#include <sys/param.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/socket.h>
-#include <sys/systm.h>
-#include <sys/errno.h>
-#include <sys/time.h>
-#include <sys/kernel.h>
-#include <sys/kernel_types.h>
-#include <sys/syslog.h>
-
-#include <kern/zalloc.h>
-
-#include <net/if.h>
-#include <net/net_osdep.h>
-#include <net/pktsched/pktsched.h>
-#include <net/pktsched/pktsched_rmclass.h>
-#include <net/pktsched/pktsched_rmclass_debug.h>
-#include <net/classq/classq_red.h>
-#include <net/classq/classq_rio.h>
-#include <net/classq/classq_blue.h>
-#include <net/classq/classq_sfb.h>
-
-/*
- * Local Macros
- */
-
-#define        reset_cutoff(ifd)       { ifd->cutoff_ = RM_MAXDEPTH; }
-
-/*
- * Local routines.
- */
-
-static int     rmc_satisfied(struct rm_class *, struct timeval *);
-static void    rmc_wrr_set_weights(struct rm_ifdat *);
-static void    rmc_depth_compute(struct rm_class *);
-static void    rmc_depth_recompute(rm_class_t *);
-
-static struct mbuf *_rmc_wrr_dequeue_next(struct rm_ifdat *, cqdq_op_t);
-static struct mbuf *_rmc_prr_dequeue_next(struct rm_ifdat *, cqdq_op_t);
-
-static int     _rmc_addq(rm_class_t *, struct mbuf *, struct pf_mtag *);
-static void    _rmc_dropq(rm_class_t *);
-static struct mbuf *_rmc_getq(rm_class_t *);
-static struct mbuf *_rmc_pollq(rm_class_t *);
-
-static int     rmc_under_limit(struct rm_class *, struct timeval *);
-static void    rmc_tl_satisfied(struct rm_ifdat *, struct timeval *);
-static void    rmc_drop_action(struct rm_class *);
-static void    rmc_restart(struct rm_class *);
-static void    rmc_root_overlimit(rm_class_t *, rm_class_t *);
-
-#define        RMC_ZONE_MAX    32              /* maximum elements in zone */
-#define        RMC_ZONE_NAME   "pktsched_cbq_cl" /* zone name (CBQ for now) */
-
-static unsigned int rmc_size;          /* size of zone element */
-static struct zone *rmc_zone;          /* zone for rm_class */
-
-void
-rmclass_init(void)
-{
-       if (rmc_zone != NULL)
-               return;
-
-       rmc_size = sizeof (struct rm_class);
-       rmc_zone = zinit(rmc_size, RMC_ZONE_MAX * rmc_size, 0, RMC_ZONE_NAME);
-       if (rmc_zone == NULL) {
-               panic("%s: failed allocating %s", __func__, RMC_ZONE_NAME);
-               /* NOTREACHED */
-       }
-       zone_change(rmc_zone, Z_EXPAND, TRUE);
-       zone_change(rmc_zone, Z_CALLERACCT, TRUE);
-}
-
-#define        BORROW_OFFTIME
-/*
- * BORROW_OFFTIME (experimental):
- * borrow the offtime of the class borrowing from.
- * the reason is that when its own offtime is set, the class is unable
- * to borrow much, especially when cutoff is taking effect.
- * but when the borrowed class is overloaded (advidle is close to minidle),
- * use the borrowing class's offtime to avoid overload.
- */
-#define        ADJUST_CUTOFF
-/*
- * ADJUST_CUTOFF (experimental):
- * if no underlimit class is found due to cutoff, increase cutoff and
- * retry the scheduling loop.
- * also, don't invoke delay_actions while cutoff is taking effect,
- * since a sleeping class won't have a chance to be scheduled in the
- * next loop.
- *
- * now heuristics for setting the top-level variable (cutoff_) becomes:
- *     1. if a packet arrives for a not-overlimit class, set cutoff
- *        to the depth of the class.
- *     2. if cutoff is i, and a packet arrives for an overlimit class
- *        with an underlimit ancestor at a lower level than i (say j),
- *        then set cutoff to j.
- *     3. at scheduling a packet, if there is no underlimit class
- *        due to the current cutoff level, increase cutoff by 1 and
- *        then try to schedule again.
- */
-
-/*
- * rm_class_t *
- * rmc_newclass(...) - Create a new resource management class at priority
- * 'pri' on the interface given by 'ifd'.
- *
- * nsecPerByte  is the data rate of the interface in nanoseconds/byte.
- *              E.g., 800 for a 10Mb/s ethernet.  If the class gets less
- *              than 100% of the bandwidth, this number should be the
- *              'effective' rate for the class.  Let f be the
- *              bandwidth fraction allocated to this class, and let
- *              nsPerByte be the data rate of the output link in
- *              nanoseconds/byte.  Then nsecPerByte is set to
- *              nsPerByte / f.  E.g., 1600 (= 800 / .5)
- *              for a class that gets 50% of an ethernet's bandwidth.
- *
- * action       the routine to call when the class is over limit.
- *
- * maxq         max allowable queue size for class (in packets).
- *
- * parent       parent class pointer.
- *
- * borrow       class to borrow from (should be either 'parent' or null).
- *
- * maxidle      max value allowed for class 'idle' time estimate (this
- *              parameter determines how large an initial burst of packets
- *              can be before overlimit action is invoked.
- *
- * offtime      how long 'delay' action will delay when class goes over
- *              limit (this parameter determines the steady-state burst
- *              size when a class is running over its limit).
- *
- * Maxidle and offtime have to be computed from the following:  If the
- * average packet size is s, the bandwidth fraction allocated to this
- * class is f, we want to allow b packet bursts, and the gain of the
- * averaging filter is g (= 1 - 2^(-RM_FILTER_GAIN)), then:
- *
- *   ptime = s * nsPerByte * (1 - f) / f
- *   maxidle = ptime * (1 - g^b) / g^b
- *   minidle = -ptime * (1 / (f - 1))
- *   offtime = ptime * (1 + 1/(1 - g) * (1 - g^(b - 1)) / g^(b - 1)
- *
- * Operationally, it's convenient to specify maxidle & offtime in units
- * independent of the link bandwidth so the maxidle & offtime passed to
- * this routine are the above values multiplied by 8*f/(1000*nsPerByte).
- * (The constant factor is a scale factor needed to make the parameters
- * integers.  This scaling also means that the 'unscaled' values of
- * maxidle*nsecPerByte/8 and offtime*nsecPerByte/8 will be in microseconds,
- * not nanoseconds.)  Also note that the 'idle' filter computation keeps
- * an estimate scaled upward by 2^RM_FILTER_GAIN so the passed value of
- * maxidle also must be scaled upward by this value.  Thus, the passed
- * values for maxidle and offtime can be computed as follows:
- *
- * maxidle = maxidle * 2^RM_FILTER_GAIN * 8 / (1000 * nsecPerByte)
- * offtime = offtime * 8 / (1000 * nsecPerByte)
- *
- * When USE_HRTIME is employed, then maxidle and offtime become:
- *     maxidle = maxilde * (8.0 / nsecPerByte);
- *     offtime = offtime * (8.0 / nsecPerByte);
- */
-struct rm_class *
-rmc_newclass(int pri, struct rm_ifdat *ifd, u_int32_t nsecPerByte,
-    void (*action)(rm_class_t *, rm_class_t *), u_int32_t qid, u_int32_t maxq,
-    struct rm_class *parent, struct rm_class *borrow, u_int32_t maxidle,
-    int minidle, u_int32_t offtime, int pktsize, int flags)
-{
-       struct ifnet *ifp;
-       struct ifclassq *ifq;
-       struct rm_class *cl;
-       struct rm_class *peer;
-
-       if (nsecPerByte == 0) {
-               log(LOG_ERR, "%s: invalid inverse data rate\n", __func__);
-               return (NULL);
-       }
-
-       if (pri >= RM_MAXPRIO) {
-               log(LOG_ERR, "%s: priority %d out of range! (max %d)\n",
-                   __func__, pri, RM_MAXPRIO - 1);
-               return (NULL);
-       }
-
-#if !CLASSQ_RED
-       if (flags & RMCF_RED) {
-               log(LOG_ERR, "%s: RED not configured for CBQ!\n", __func__);
-               return (NULL);
-       }
-#endif /* !CLASSQ_RED */
-
-#if !CLASSQ_RIO
-       if (flags & RMCF_RIO) {
-               log(LOG_ERR, "%s: RIO not configured for CBQ!\n", __func__);
-               return (NULL);
-       }
-#endif /* CLASSQ_RIO */
-
-#if !CLASSQ_BLUE
-       if (flags & RMCF_BLUE) {
-               log(LOG_ERR, "%s: BLUE not configured for CBQ!\n", __func__);
-               return (NULL);
-       }
-#endif /* CLASSQ_BLUE */
-
-       /* These are mutually exclusive */
-       if ((flags & (RMCF_RED|RMCF_RIO|RMCF_BLUE|RMCF_SFB)) &&
-           (flags & (RMCF_RED|RMCF_RIO|RMCF_BLUE|RMCF_SFB)) != RMCF_RED &&
-           (flags & (RMCF_RED|RMCF_RIO|RMCF_BLUE|RMCF_SFB)) != RMCF_RIO &&
-           (flags & (RMCF_RED|RMCF_RIO|RMCF_BLUE|RMCF_SFB)) != RMCF_BLUE &&
-           (flags & (RMCF_RED|RMCF_RIO|RMCF_BLUE|RMCF_SFB)) != RMCF_SFB) {
-               log(LOG_ERR, "%s: RED|RIO|BLUE|SFB mutually exclusive\n",
-                   __func__);
-               return (NULL);
-       }
-
-       cl = zalloc(rmc_zone);
-       if (cl == NULL)
-               return (NULL);
-
-       bzero(cl, rmc_size);
-       CALLOUT_INIT(&cl->callout_);
-
-       /*
-        * Class initialization.
-        */
-       cl->children_ = NULL;
-       cl->parent_ = parent;
-       cl->borrow_ = borrow;
-       cl->leaf_ = 1;
-       cl->ifdat_ = ifd;
-       cl->pri_ = pri;
-       cl->allotment_ = RM_NS_PER_SEC / nsecPerByte; /* Bytes per sec */
-       cl->depth_ = 0;
-       cl->qthresh_ = 0;
-       cl->ns_per_byte_ = nsecPerByte;
-
-       ifq = ifd->ifq_;
-       ifp = ifq->ifcq_ifp;
-
-       if (maxq == 0 || maxq > IFCQ_MAXLEN(ifq)) {
-               maxq = IFCQ_MAXLEN(ifq);
-               if (maxq == 0)
-                       maxq = DEFAULT_QLIMIT;  /* use default */
-       }
-       _qinit(&cl->q_, Q_DROPHEAD, maxq);
-
-       cl->flags_ = flags;
-
-       cl->minidle_ = (minidle * (int)nsecPerByte) / 8;
-       if (cl->minidle_ > 0)
-               cl->minidle_ = 0;
-
-       cl->maxidle_ = (maxidle * nsecPerByte) / 8;
-       if (cl->maxidle_ == 0)
-               cl->maxidle_ = 1;
-
-       cl->avgidle_ = cl->maxidle_;
-       cl->offtime_ = ((offtime * nsecPerByte) / 8) >> RM_FILTER_GAIN;
-       if (cl->offtime_ == 0)
-               cl->offtime_ = 1;
-
-       cl->overlimit = action;
-
-       if (flags & (RMCF_RED|RMCF_RIO|RMCF_BLUE|RMCF_SFB)) {
-               int pkttime;
-
-               cl->qflags_ = 0;
-               if (flags & RMCF_ECN) {
-                       if (flags & RMCF_BLUE)
-                               cl->qflags_ |= BLUEF_ECN;
-                       else if (flags & RMCF_SFB)
-                               cl->qflags_ |= SFBF_ECN;
-                       else if (flags & RMCF_RED)
-                               cl->qflags_ |= REDF_ECN;
-                       else if (flags & RMCF_RIO)
-                               cl->qflags_ |= RIOF_ECN;
-               }
-               if (flags & RMCF_FLOWCTL) {
-                       if (flags & RMCF_SFB)
-                               cl->qflags_ |= SFBF_FLOWCTL;
-               }
-               if (flags & RMCF_FLOWVALVE) {
-                       if (flags & RMCF_RED)
-                               cl->qflags_ |= REDF_FLOWVALVE;
-               }
-               if (flags & RMCF_CLEARDSCP) {
-                       if (flags & RMCF_RIO)
-                               cl->qflags_ |= RIOF_CLEARDSCP;
-               }
-               pkttime = nsecPerByte * pktsize  / 1000;
-
-               /* Test for exclusivity {RED,RIO,BLUE,SFB} was done above */
-#if CLASSQ_RED
-               if (flags & RMCF_RED) {
-                       cl->red_ = red_alloc(ifp, 0, 0,
-                           qlimit(&cl->q_) * 10/100,
-                           qlimit(&cl->q_) * 30/100,
-                           cl->qflags_, pkttime);
-                       if (cl->red_ != NULL)
-                               qtype(&cl->q_) = Q_RED;
-               }
-#endif /* CLASSQ_RED */
-#if CLASSQ_RIO
-               if (flags & RMCF_RIO) {
-                       cl->rio_ =
-                           rio_alloc(ifp, 0, NULL, cl->qflags_, pkttime);
-                       if (cl->rio_ != NULL)
-                               qtype(&cl->q_) = Q_RIO;
-               }
-#endif /* CLASSQ_RIO */
-#if CLASSQ_BLUE
-               if (flags & RMCF_BLUE) {
-                       cl->blue_ = blue_alloc(ifp, 0, 0, cl->qflags_);
-                       if (cl->blue_ != NULL)
-                               qtype(&cl->q_) = Q_BLUE;
-               }
-#endif /* CLASSQ_BLUE */
-               if (flags & RMCF_SFB) {
-                       if (!(cl->flags_ & RMCF_LAZY))
-                               cl->sfb_ = sfb_alloc(ifp, qid,
-                                   qlimit(&cl->q_), cl->qflags_);
-                       if (cl->sfb_ != NULL || (cl->flags_ & RMCF_LAZY))
-                               qtype(&cl->q_) = Q_SFB;
-               }
-       }
-
-       /*
-        * put the class into the class tree
-        */
-       if ((peer = ifd->active_[pri]) != NULL) {
-               /* find the last class at this pri */
-               cl->peer_ = peer;
-               while (peer->peer_ != ifd->active_[pri])
-                       peer = peer->peer_;
-               peer->peer_ = cl;
-       } else {
-               ifd->active_[pri] = cl;
-               cl->peer_ = cl;
-       }
-
-       if (cl->parent_) {
-               cl->next_ = parent->children_;
-               parent->children_ = cl;
-               parent->leaf_ = 0;
-       }
-
-       /*
-        * Compute the depth of this class and its ancestors in the class
-        * hierarchy.
-        */
-       rmc_depth_compute(cl);
-
-       /*
-        * If CBQ's WRR is enabled, then initialize the class WRR state.
-        */
-       if (ifd->wrr_) {
-               ifd->num_[pri]++;
-               ifd->alloc_[pri] += cl->allotment_;
-               rmc_wrr_set_weights(ifd);
-       }
-       return (cl);
-}
-
-int
-rmc_modclass(struct rm_class *cl, u_int32_t nsecPerByte, int maxq,
-    u_int32_t maxidle, int minidle, u_int32_t offtime, int pktsize)
-{
-#pragma unused(pktsize)
-       struct rm_ifdat *ifd;
-       u_int32_t        old_allotment;
-
-       ifd = cl->ifdat_;
-       old_allotment = cl->allotment_;
-
-       cl->allotment_ = RM_NS_PER_SEC / nsecPerByte; /* Bytes per sec */
-       cl->qthresh_ = 0;
-       cl->ns_per_byte_ = nsecPerByte;
-
-       qlimit(&cl->q_) = maxq;
-
-       cl->minidle_ = (minidle * nsecPerByte) / 8;
-       if (cl->minidle_ > 0)
-               cl->minidle_ = 0;
-
-       cl->maxidle_ = (maxidle * nsecPerByte) / 8;
-       if (cl->maxidle_ == 0)
-               cl->maxidle_ = 1;
-
-       cl->avgidle_ = cl->maxidle_;
-       cl->offtime_ = ((offtime * nsecPerByte) / 8) >> RM_FILTER_GAIN;
-       if (cl->offtime_ == 0)
-               cl->offtime_ = 1;
-
-       /*
-        * If CBQ's WRR is enabled, then initialize the class WRR state.
-        */
-       if (ifd->wrr_) {
-               ifd->alloc_[cl->pri_] += cl->allotment_ - old_allotment;
-               rmc_wrr_set_weights(ifd);
-       }
-       return (0);
-}
-
-/*
- * static void
- * rmc_wrr_set_weights(struct rm_ifdat *ifdat) - This function computes
- *     the appropriate run robin weights for the CBQ weighted round robin
- *     algorithm.
- *
- *     Returns: NONE
- */
-
-static void
-rmc_wrr_set_weights(struct rm_ifdat *ifd)
-{
-       int             i;
-       struct rm_class *cl, *clh;
-
-       for (i = 0; i < RM_MAXPRIO; i++) {
-               /*
-                * This is inverted from that of the simulator to
-                * maintain precision.
-                */
-               if (ifd->num_[i] == 0) {
-                       ifd->M_[i] = 0;
-               } else {
-                       ifd->M_[i] =
-                           ifd->alloc_[i] / (ifd->num_[i] * ifd->maxpkt_);
-               }
-               /*
-                * Compute the weighted allotment for each class.
-                * This takes the expensive div instruction out
-                * of the main loop for the wrr scheduling path.
-                * These only get recomputed when a class comes or
-                * goes.
-                */
-               if (ifd->active_[i] != NULL) {
-                       clh = cl = ifd->active_[i];
-                       do {
-                               /* safe-guard for slow link or alloc_ == 0 */
-                               if (ifd->M_[i] == 0) {
-                                       cl->w_allotment_ = 0;
-                               } else {
-                                       cl->w_allotment_ =
-                                           cl->allotment_ / ifd->M_[i];
-                               }
-                               cl = cl->peer_;
-                       } while ((cl != NULL) && (cl != clh));
-               }
-       }
-}
-
-int
-rmc_get_weight(struct rm_ifdat *ifd, int pri)
-{
-       if ((pri >= 0) && (pri < RM_MAXPRIO))
-               return (ifd->M_[pri]);
-       else
-               return (0);
-}
-
-/*
- * static void
- * rmc_depth_compute(struct rm_class *cl) - This function computes the
- *     appropriate depth of class 'cl' and its ancestors.
- *
- *     Returns:        NONE
- */
-
-static void
-rmc_depth_compute(struct rm_class *cl)
-{
-       rm_class_t      *t = cl, *p;
-
-       /*
-        * Recompute the depth for the branch of the tree.
-        */
-       while (t != NULL) {
-               p = t->parent_;
-               if (p && (t->depth_ >= p->depth_)) {
-                       p->depth_ = t->depth_ + 1;
-                       t = p;
-               } else
-                       t = NULL;
-       }
-}
-
-/*
- * static void
- * rmc_depth_recompute(struct rm_class *cl) - This function re-computes
- *     the depth of the tree after a class has been deleted.
- *
- *     Returns:        NONE
- */
-
-static void
-rmc_depth_recompute(rm_class_t *cl)
-{
-       rm_class_t      *p, *t;
-
-       p = cl;
-       while (p != NULL) {
-               if ((t = p->children_) == NULL) {
-                       p->depth_ = 0;
-               } else {
-                       int cdepth = 0;
-
-                       while (t != NULL) {
-                               if (t->depth_ > cdepth)
-                                       cdepth = t->depth_;
-                               t = t->next_;
-                       }
-
-                       if (p->depth_ == cdepth + 1)
-                               /* no change to this parent */
-                               return;
-
-                       p->depth_ = cdepth + 1;
-               }
-
-               p = p->parent_;
-       }
-}
-
-/*
- * void
- * rmc_delete_class(struct rm_ifdat *ifdat, struct rm_class *cl) - This
- *     function deletes a class from the link-sharing structure and frees
- *     all resources associated with the class.
- *
- *     Returns: NONE
- */
-
-void
-rmc_delete_class(struct rm_ifdat *ifd, struct rm_class *cl)
-{
-       struct rm_class *p, *head, *previous;
-
-       VERIFY(cl->children_ == NULL);
-
-       if (cl->sleeping_)
-               CALLOUT_STOP(&cl->callout_);
-
-       /*
-        * Free packets in the packet queue.
-        * XXX - this may not be a desired behavior.  Packets should be
-        *              re-queued.
-        */
-       rmc_dropall(cl);
-
-       /*
-        * If the class has a parent, then remove the class from the
-        * class from the parent's children chain.
-        */
-       if (cl->parent_ != NULL) {
-               head = cl->parent_->children_;
-               p = previous = head;
-               if (head->next_ == NULL) {
-                       VERIFY(head == cl);
-                       cl->parent_->children_ = NULL;
-                       cl->parent_->leaf_ = 1;
-               } else while (p != NULL) {
-                       if (p == cl) {
-                               if (cl == head)
-                                       cl->parent_->children_ = cl->next_;
-                               else
-                                       previous->next_ = cl->next_;
-                               cl->next_ = NULL;
-                               p = NULL;
-                       } else {
-                               previous = p;
-                               p = p->next_;
-                       }
-               }
-       }
-
-       /*
-        * Delete class from class priority peer list.
-        */
-       if ((p = ifd->active_[cl->pri_]) != NULL) {
-               /*
-                * If there is more than one member of this priority
-                * level, then look for class(cl) in the priority level.
-                */
-               if (p != p->peer_) {
-                       while (p->peer_ != cl)
-                               p = p->peer_;
-                       p->peer_ = cl->peer_;
-
-                       if (ifd->active_[cl->pri_] == cl)
-                               ifd->active_[cl->pri_] = cl->peer_;
-               } else {
-                       VERIFY(p == cl);
-                       ifd->active_[cl->pri_] = NULL;
-               }
-       }
-
-       /*
-        * Recompute the WRR weights.
-        */
-       if (ifd->wrr_) {
-               ifd->alloc_[cl->pri_] -= cl->allotment_;
-               ifd->num_[cl->pri_]--;
-               rmc_wrr_set_weights(ifd);
-       }
-
-       /*
-        * Re-compute the depth of the tree.
-        */
-       rmc_depth_recompute(cl->parent_);
-
-       /*
-        * Free the class structure.
-        */
-       if (cl->qalg_.ptr != NULL) {
-#if CLASSQ_RIO
-               if (q_is_rio(&cl->q_))
-                       rio_destroy(cl->rio_);
-#endif /* CLASSQ_RIO */
-#if CLASSQ_RED
-               if (q_is_red(&cl->q_))
-                       red_destroy(cl->red_);
-#endif /* CLASSQ_RED */
-#if CLASSQ_BLUE
-               if (q_is_blue(&cl->q_))
-                       blue_destroy(cl->blue_);
-#endif /* CLASSQ_BLUE */
-               if (q_is_sfb(&cl->q_) && cl->sfb_ != NULL)
-                       sfb_destroy(cl->sfb_);
-               cl->qalg_.ptr = NULL;
-               qtype(&cl->q_) = Q_DROPTAIL;
-               qstate(&cl->q_) = QS_RUNNING;
-       }
-       zfree(rmc_zone, cl);
-}
-
-
-/*
- * int
- * rmc_init(...) - Initialize the resource management data structures
- *     associated with the output portion of interface 'ifp'.  'ifd' is
- *     where the structures will be built (for backwards compatibility, the
- *     structures aren't kept in the ifnet struct).  'nsecPerByte'
- *     gives the link speed (inverse of bandwidth) in nanoseconds/byte.
- *     'restart' is the driver-specific routine that the generic 'delay
- *     until under limit' action will call to restart output.  `maxq'
- *     is the queue size of the 'link' & 'default' classes.  'maxqueued'
- *     is the maximum number of packets that the resource management
- *     code will allow to be queued 'downstream' (this is typically 1).
- *
- *     Returns:        0 on success
- */
-
-int
-rmc_init(struct ifclassq *ifq, struct rm_ifdat *ifd, u_int32_t nsecPerByte,
-    void (*restart)(struct ifclassq *), u_int32_t qid, int maxq, int maxqueued,
-    u_int32_t maxidle, int minidle, u_int32_t offtime, int flags)
-{
-       struct ifnet *ifp = ifq->ifcq_ifp;
-       int i, mtu;
-
-       /*
-        * Initialize the CBQ tracing/debug facility.
-        */
-       CBQTRACEINIT();
-
-       if (nsecPerByte == 0) {
-               log(LOG_ERR, "%s: %s: invalid inverse data rate)\n",
-                   __func__, if_name(ifp));
-               return (EINVAL);
-       }
-
-       mtu = ifp->if_mtu;
-       if (mtu < 1) {
-               log(LOG_ERR, "%s: %s: invalid MTU (interface not "
-                   "initialized?)\n", __func__, if_name(ifp));
-               return (EINVAL);
-       }
-       bzero((char *)ifd, sizeof (*ifd));
-
-       ifd->ifq_ = ifq;
-       ifd->restart = restart;
-       ifd->maxqueued_ = maxqueued;
-       ifd->ns_per_byte_ = nsecPerByte;
-       ifd->maxpkt_ = mtu;
-       ifd->wrr_ = (flags & RMCF_WRR) ? 1 : 0;
-       ifd->efficient_ = (flags & RMCF_EFFICIENT) ? 1 : 0;
-#if 1
-       ifd->maxiftime_ = mtu * nsecPerByte / 1000 * 16;
-       if (mtu * nsecPerByte > 10 * 1000000)
-               ifd->maxiftime_ /= 4;
-#endif
-
-       reset_cutoff(ifd);
-       CBQTRACE(rmc_init, 'INIT', ifd->cutoff_);
-
-       /*
-        * Initialize the CBQ's WRR state.
-        */
-       for (i = 0; i < RM_MAXPRIO; i++) {
-               ifd->alloc_[i] = 0;
-               ifd->M_[i] = 0;
-               ifd->num_[i] = 0;
-               ifd->na_[i] = 0;
-               ifd->active_[i] = NULL;
-       }
-
-       /*
-        * Initialize current packet state.
-        */
-       ifd->qi_ = 0;
-       ifd->qo_ = 0;
-       for (i = 0; i < RM_MAXQUEUED; i++) {
-               ifd->class_[i] = NULL;
-               ifd->curlen_[i] = 0;
-               ifd->borrowed_[i] = NULL;
-       }
-
-       /*
-        * Create the root class of the link-sharing structure.
-        */
-       if ((ifd->root_ = rmc_newclass(0, ifd, nsecPerByte,
-           rmc_root_overlimit, qid, maxq, 0, 0, maxidle, minidle, offtime,
-           0, 0)) == NULL) {
-               log(LOG_ERR, "rmc_init: root class not allocated\n");
-               return (ENOMEM);
-       }
-       ifd->root_->depth_ = 0;
-
-       return (0);
-}
-
-/*
- * void
- * rmc_queue_packet(struct rm_class *cl, struct mbuf *m) - Add packet given by
- *     mbuf 'm' to queue for resource class 'cl'.  This routine is called
- *     by a driver's if_output routine.  This routine must be called with
- *     output packet completion interrupts locked out (to avoid racing with
- *     rmc_dequeue_next).
- *
- *     Returns:        0 on successful queueing
- *                     CLASSQEQ_DROPPED when packet drop occurs
- */
-int
-rmc_queue_packet(struct rm_class *cl, struct mbuf *m, struct pf_mtag *t)
-{
-       struct timeval   now;
-       struct rm_ifdat *ifd = cl->ifdat_;
-       int              cpri = cl->pri_;
-       int              is_empty = qempty(&cl->q_);
-       int ret = 0;
-
-       RM_GETTIME(now);
-       if (ifd->cutoff_ > 0) {
-               if (TV_LT(&cl->undertime_, &now)) {
-                       if (ifd->cutoff_ > cl->depth_)
-                               ifd->cutoff_ = cl->depth_;
-                       CBQTRACE(rmc_queue_packet, 'ffoc', cl->depth_);
-               } else {
-                       /*
-                        * the class is overlimit. if the class has
-                        * underlimit ancestors, set cutoff to the lowest
-                        * depth among them.
-                        */
-                       struct rm_class *borrow = cl->borrow_;
-
-                       while (borrow != NULL &&
-                           borrow->depth_ < ifd->cutoff_) {
-                               if (TV_LT(&borrow->undertime_, &now)) {
-                                       ifd->cutoff_ = borrow->depth_;
-                                       CBQTRACE(rmc_queue_packet, 'ffob',
-                                           ifd->cutoff_);
-                                       break;
-                               }
-                               borrow = borrow->borrow_;
-                       }
-               }
-       }
-
-       ret = _rmc_addq(cl, m, t);
-       if (ret != 0 &&
-           (ret == CLASSQEQ_DROPPED || ret == CLASSQEQ_DROPPED_FC ||
-           ret == CLASSQEQ_DROPPED_SP)) {
-               /* failed */
-               return (ret);
-       }
-       VERIFY(ret == 0 || ret == CLASSQEQ_SUCCESS_FC);
-       if (is_empty) {
-               CBQTRACE(rmc_queue_packet, 'type', cl->stats_.handle);
-               ifd->na_[cpri]++;
-       }
-
-       if (qlen(&cl->q_) > qlimit(&cl->q_)) {
-               /* note: qlimit can be set to 0 or 1 */
-               rmc_drop_action(cl);
-               return (CLASSQEQ_DROPPED);
-       }
-       return (ret);
-}
-
-/*
- * void
- * rmc_tl_satisfied(struct rm_ifdat *ifd, struct timeval *now) - Check all
- *     classes to see if there are satified.
- */
-
-static void
-rmc_tl_satisfied(struct rm_ifdat *ifd, struct timeval *now)
-{
-       int              i;
-       rm_class_t      *p, *bp;
-
-       for (i = RM_MAXPRIO - 1; i >= 0; i--) {
-               if ((bp = ifd->active_[i]) != NULL) {
-                       p = bp;
-                       do {
-                               if (!rmc_satisfied(p, now)) {
-                                       ifd->cutoff_ = p->depth_;
-                                       return;
-                               }
-                               p = p->peer_;
-                       } while (p != bp);
-               }
-       }
-
-       reset_cutoff(ifd);
-}
-
-/*
- * rmc_satisfied - Return 1 of the class is satisfied.  O, otherwise.
- */
-
-static int
-rmc_satisfied(struct rm_class *cl, struct timeval *now)
-{
-       rm_class_t      *p;
-
-       if (cl == NULL)
-               return (1);
-       if (TV_LT(now, &cl->undertime_))
-               return (1);
-       if (cl->depth_ == 0) {
-               if (!cl->sleeping_ && (qlen(&cl->q_) > cl->qthresh_))
-                       return (0);
-               else
-                       return (1);
-       }
-       if (cl->children_ != NULL) {
-               p = cl->children_;
-               while (p != NULL) {
-                       if (!rmc_satisfied(p, now))
-                               return (0);
-                       p = p->next_;
-               }
-       }
-
-       return (1);
-}
-
-/*
- * Return 1 if class 'cl' is under limit or can borrow from a parent,
- * 0 if overlimit.  As a side-effect, this routine will invoke the
- * class overlimit action if the class if overlimit.
- */
-
-static int
-rmc_under_limit(struct rm_class *cl, struct timeval *now)
-{
-       rm_class_t      *p = cl;
-       rm_class_t      *top;
-       struct rm_ifdat *ifd = cl->ifdat_;
-
-       ifd->borrowed_[ifd->qi_] = NULL;
-       /*
-        * If cl is the root class, then always return that it is
-        * underlimit.  Otherwise, check to see if the class is underlimit.
-        */
-       if (cl->parent_ == NULL)
-               return (1);
-
-       if (cl->sleeping_) {
-               if (TV_LT(now, &cl->undertime_))
-                       return (0);
-
-               CALLOUT_STOP(&cl->callout_);
-               cl->sleeping_ = 0;
-               cl->undertime_.tv_sec = 0;
-               return (1);
-       }
-
-       top = NULL;
-       while (cl->undertime_.tv_sec && TV_LT(now, &cl->undertime_)) {
-               if (((cl = cl->borrow_) == NULL) ||
-                   (cl->depth_ > ifd->cutoff_)) {
-#ifdef ADJUST_CUTOFF
-                       if (cl != NULL)
-                               /*
-                                * cutoff is taking effect, just
-                                * return false without calling
-                                * the delay action.
-                                */
-                               return (0);
-#endif
-#ifdef BORROW_OFFTIME
-                       /*
-                        * check if the class can borrow offtime too.
-                        * borrow offtime from the top of the borrow
-                        * chain if the top class is not overloaded.
-                        */
-                       if (cl != NULL) {
-                               /*
-                                * cutoff is taking effect, use this
-                                * class as top.
-                                */
-                               top = cl;
-                               CBQTRACE(rmc_under_limit, 'ffou', ifd->cutoff_);
-                       }
-                       if (top != NULL && top->avgidle_ == top->minidle_)
-                               top = NULL;
-                       p->overtime_ = *now;
-                       (p->overlimit)(p, top);
-#else
-                       p->overtime_ = *now;
-                       (p->overlimit)(p, NULL);
-#endif
-                       return (0);
-               }
-               top = cl;
-       }
-
-       if (cl != p)
-               ifd->borrowed_[ifd->qi_] = cl;
-       return (1);
-}
-
-/*
- * _rmc_wrr_dequeue_next() - This is scheduler for WRR as opposed to
- *     Packet-by-packet round robin.
- *
- * The heart of the weighted round-robin scheduler, which decides which
- * class next gets to send a packet.  Highest priority first, then
- * weighted round-robin within priorites.
- *
- * Each able-to-send class gets to send until its byte allocation is
- * exhausted.  Thus, the active pointer is only changed after a class has
- * exhausted its allocation.
- *
- * If the scheduler finds no class that is underlimit or able to borrow,
- * then the first class found that had a nonzero queue and is allowed to
- * borrow gets to send.
- */
-
-static struct mbuf *
-_rmc_wrr_dequeue_next(struct rm_ifdat *ifd, cqdq_op_t op)
-{
-       struct rm_class *cl = NULL, *first = NULL;
-       u_int32_t        deficit;
-       int              cpri;
-       struct mbuf     *m;
-       struct timeval   now;
-
-       RM_GETTIME(now);
-
-       /*
-        * if the driver polls the top of the queue and then removes
-        * the polled packet, we must return the same packet.
-        */
-       if (op == CLASSQDQ_REMOVE && ifd->pollcache_) {
-               cl = ifd->pollcache_;
-               cpri = cl->pri_;
-               if (ifd->efficient_) {
-                       /* check if this class is overlimit */
-                       if (cl->undertime_.tv_sec != 0 &&
-                           rmc_under_limit(cl, &now) == 0)
-                               first = cl;
-               }
-               ifd->pollcache_ = NULL;
-               goto _wrr_out;
-       } else {
-               /* mode == CLASSQDQ_POLL || pollcache == NULL */
-               ifd->pollcache_ = NULL;
-               ifd->borrowed_[ifd->qi_] = NULL;
-       }
-#ifdef ADJUST_CUTOFF
-_again:
-#endif
-       for (cpri = RM_MAXPRIO - 1; cpri >= 0; cpri--) {
-               if (ifd->na_[cpri] == 0)
-                       continue;
-               deficit = 0;
-               /*
-                * Loop through twice for a priority level, if some class
-                * was unable to send a packet the first round because
-                * of the weighted round-robin mechanism.
-                * During the second loop at this level, deficit==2.
-                * (This second loop is not needed if for every class,
-                * "M[cl->pri_])" times "cl->allotment" is greater than
-                * the byte size for the largest packet in the class.)
-                */
-_wrr_loop:
-               cl = ifd->active_[cpri];
-               VERIFY(cl != NULL);
-               do {
-                       if ((deficit < 2) && (cl->bytes_alloc_ <= 0))
-                               cl->bytes_alloc_ += cl->w_allotment_;
-                       if (!qempty(&cl->q_)) {
-                               if ((cl->undertime_.tv_sec == 0) ||
-                                   rmc_under_limit(cl, &now)) {
-                                       if (cl->bytes_alloc_ > 0 || deficit > 1)
-                                               goto _wrr_out;
-
-                                       /* underlimit but no alloc */
-                                       deficit = 1;
-#if 1
-                                       ifd->borrowed_[ifd->qi_] = NULL;
-#endif
-                               } else if (first == NULL && cl->borrow_ != NULL)
-                                       first = cl; /* borrowing candidate */
-                       }
-
-                       cl->bytes_alloc_ = 0;
-                       cl = cl->peer_;
-               } while (cl != ifd->active_[cpri]);
-
-               if (deficit == 1) {
-                       /* first loop found an underlimit class with deficit */
-                       /* Loop on same priority level, with new deficit.  */
-                       deficit = 2;
-                       goto _wrr_loop;
-               }
-       }
-
-#ifdef ADJUST_CUTOFF
-       /*
-        * no underlimit class found.  if cutoff is taking effect,
-        * increase cutoff and try again.
-        */
-       if (first != NULL && ifd->cutoff_ < ifd->root_->depth_) {
-               ifd->cutoff_++;
-               CBQTRACE(_rmc_wrr_dequeue_next, 'ojda', ifd->cutoff_);
-               goto _again;
-       }
-#endif /* ADJUST_CUTOFF */
-       /*
-        * If LINK_EFFICIENCY is turned on, then the first overlimit
-        * class we encounter will send a packet if all the classes
-        * of the link-sharing structure are overlimit.
-        */
-       reset_cutoff(ifd);
-       CBQTRACE(_rmc_wrr_dequeue_next, 'otsr', ifd->cutoff_);
-
-       if (!ifd->efficient_ || first == NULL)
-               return (NULL);
-
-       cl = first;
-       cpri = cl->pri_;
-#if 0  /* too time-consuming for nothing */
-       if (cl->sleeping_)
-               CALLOUT_STOP(&cl->callout_);
-       cl->sleeping_ = 0;
-       cl->undertime_.tv_sec = 0;
-#endif
-       ifd->borrowed_[ifd->qi_] = cl->borrow_;
-       ifd->cutoff_ = cl->borrow_->depth_;
-
-       /*
-        * Deque the packet and do the book keeping...
-        */
-_wrr_out:
-       if (op == CLASSQDQ_REMOVE) {
-               m = _rmc_getq(cl);
-               if (m == NULL)
-                       return (NULL);
-
-               if (qempty(&cl->q_))
-                       ifd->na_[cpri]--;
-
-               /*
-                * Update class statistics and link data.
-                */
-               if (cl->bytes_alloc_ > 0)
-                       cl->bytes_alloc_ -= m_pktlen(m);
-
-               if ((cl->bytes_alloc_ <= 0) || first == cl)
-                       ifd->active_[cl->pri_] = cl->peer_;
-               else
-                       ifd->active_[cl->pri_] = cl;
-
-               ifd->class_[ifd->qi_] = cl;
-               ifd->curlen_[ifd->qi_] = m_pktlen(m);
-               ifd->now_[ifd->qi_] = now;
-               ifd->qi_ = (ifd->qi_ + 1) % ifd->maxqueued_;
-               ifd->queued_++;
-       } else {
-               /* mode == ALTDQ_PPOLL */
-               m = _rmc_pollq(cl);
-               ifd->pollcache_ = cl;
-       }
-       return (m);
-}
-
-/*
- * Dequeue & return next packet from the highest priority class that
- * has a packet to send & has enough allocation to send it.  This
- * routine is called by a driver whenever it needs a new packet to
- * output.
- */
-static struct mbuf *
-_rmc_prr_dequeue_next(struct rm_ifdat *ifd, cqdq_op_t op)
-{
-       struct mbuf     *m;
-       int              cpri;
-       struct rm_class *cl, *first = NULL;
-       struct timeval   now;
-
-       RM_GETTIME(now);
-
-       /*
-        * if the driver polls the top of the queue and then removes
-        * the polled packet, we must return the same packet.
-        */
-       if (op == CLASSQDQ_REMOVE && ifd->pollcache_) {
-               cl = ifd->pollcache_;
-               cpri = cl->pri_;
-               ifd->pollcache_ = NULL;
-               goto _prr_out;
-       } else {
-               /* mode == CLASSQDQ_POLL || pollcache == NULL */
-               ifd->pollcache_ = NULL;
-               ifd->borrowed_[ifd->qi_] = NULL;
-       }
-#ifdef ADJUST_CUTOFF
-_again:
-#endif
-       for (cpri = RM_MAXPRIO - 1; cpri >= 0; cpri--) {
-               if (ifd->na_[cpri] == 0)
-                       continue;
-               cl = ifd->active_[cpri];
-               VERIFY(cl != NULL);
-               do {
-                       if (!qempty(&cl->q_)) {
-                               if ((cl->undertime_.tv_sec == 0) ||
-                                   rmc_under_limit(cl, &now))
-                                       goto _prr_out;
-                               if (first == NULL && cl->borrow_ != NULL)
-                                       first = cl;
-                       }
-                       cl = cl->peer_;
-               } while (cl != ifd->active_[cpri]);
-       }
-
-#ifdef ADJUST_CUTOFF
-       /*
-        * no underlimit class found.  if cutoff is taking effect, increase
-        * cutoff and try again.
-        */
-       if (first != NULL && ifd->cutoff_ < ifd->root_->depth_) {
-               ifd->cutoff_++;
-               goto _again;
-       }
-#endif /* ADJUST_CUTOFF */
-       /*
-        * If LINK_EFFICIENCY is turned on, then the first overlimit
-        * class we encounter will send a packet if all the classes
-        * of the link-sharing structure are overlimit.
-        */
-       reset_cutoff(ifd);
-       if (!ifd->efficient_ || first == NULL)
-               return (NULL);
-
-       cl = first;
-       cpri = cl->pri_;
-#if 0  /* too time-consuming for nothing */
-       if (cl->sleeping_)
-               CALLOUT_STOP(&cl->callout_);
-       cl->sleeping_ = 0;
-       cl->undertime_.tv_sec = 0;
-#endif
-       ifd->borrowed_[ifd->qi_] = cl->borrow_;
-       ifd->cutoff_ = cl->borrow_->depth_;
-
-       /*
-        * Deque the packet and do the book keeping...
-        */
-_prr_out:
-       if (op == CLASSQDQ_REMOVE) {
-               m = _rmc_getq(cl);
-               if (m == NULL)
-                       return (NULL);
-
-               if (qempty(&cl->q_))
-                       ifd->na_[cpri]--;
-
-               ifd->active_[cpri] = cl->peer_;
-
-               ifd->class_[ifd->qi_] = cl;
-               ifd->curlen_[ifd->qi_] = m_pktlen(m);
-               ifd->now_[ifd->qi_] = now;
-               ifd->qi_ = (ifd->qi_ + 1) % ifd->maxqueued_;
-               ifd->queued_++;
-       } else {
-               /* mode == CLASSQDQ_POLL */
-               m = _rmc_pollq(cl);
-               ifd->pollcache_ = cl;
-       }
-       return (m);
-}
-
-/*
- * struct mbuf *
- * rmc_dequeue_next(struct rm_ifdat *ifd, struct timeval *now) - this function
- *     is invoked by the packet driver to get the next packet to be
- *     dequeued and output on the link.  If WRR is enabled, then the
- *     WRR dequeue next routine will determine the next packet to sent.
- *     Otherwise, packet-by-packet round robin is invoked.
- *
- *     Returns:        NULL, if a packet is not available or if all
- *                     classes are overlimit.
- *
- *                     Otherwise, Pointer to the next packet.
- */
-
-struct mbuf *
-rmc_dequeue_next(struct rm_ifdat *ifd, cqdq_op_t mode)
-{
-       if (ifd->queued_ >= ifd->maxqueued_)
-               return (NULL);
-       else if (ifd->wrr_)
-               return (_rmc_wrr_dequeue_next(ifd, mode));
-       else
-               return (_rmc_prr_dequeue_next(ifd, mode));
-}
-
-/*
- * Update the utilization estimate for the packet that just completed.
- * The packet's class & the parent(s) of that class all get their
- * estimators updated.  This routine is called by the driver's output-
- * packet-completion interrupt service routine.
- */
-
-/*
- * a macro to approximate "divide by 1000" that gives 0.000999,
- * if a value has enough effective digits.
- * (on pentium, mul takes 9 cycles but div takes 46!)
- */
-#define        NSEC_TO_USEC(t) (((t) >> 10) + ((t) >> 16) + ((t) >> 17))
-void
-rmc_update_class_util(struct rm_ifdat *ifd)
-{
-       int              idle, avgidle, pktlen;
-       int              pkt_time, tidle;
-       rm_class_t      *cl, *borrowed;
-       rm_class_t      *borrows;
-       struct timeval  *nowp;
-
-       /*
-        * Get the most recent completed class.
-        */
-       if ((cl = ifd->class_[ifd->qo_]) == NULL)
-               return;
-
-       pktlen = ifd->curlen_[ifd->qo_];
-       borrowed = ifd->borrowed_[ifd->qo_];
-       borrows = borrowed;
-
-       PKTCNTR_ADD(&cl->stats_.xmit_cnt, 1, pktlen);
-
-       /*
-        * Run estimator on class and its ancestors.
-        */
-       /*
-        * rm_update_class_util is designed to be called when the
-        * transfer is completed from a xmit complete interrupt,
-        * but most drivers don't implement an upcall for that.
-        * so, just use estimated completion time.
-        * as a result, ifd->qi_ and ifd->qo_ are always synced.
-        */
-       nowp = &ifd->now_[ifd->qo_];
-       /* get pkt_time (for link) in usec */
-#if 1  /* use approximation */
-       pkt_time = ifd->curlen_[ifd->qo_] * ifd->ns_per_byte_;
-       pkt_time = NSEC_TO_USEC(pkt_time);
-#else
-       pkt_time = ifd->curlen_[ifd->qo_] * ifd->ns_per_byte_ / 1000;
-#endif
-#if 1 /* ALTQ4PPP */
-       if (TV_LT(nowp, &ifd->ifnow_)) {
-               int iftime;
-
-               /*
-                * make sure the estimated completion time does not go
-                * too far.  it can happen when the link layer supports
-                * data compression or the interface speed is set to
-                * a much lower value.
-                */
-               TV_DELTA(&ifd->ifnow_, nowp, iftime);
-               if (iftime+pkt_time < ifd->maxiftime_) {
-                       TV_ADD_DELTA(&ifd->ifnow_, pkt_time, &ifd->ifnow_);
-               } else {
-                       TV_ADD_DELTA(nowp, ifd->maxiftime_, &ifd->ifnow_);
-               }
-       } else {
-               TV_ADD_DELTA(nowp, pkt_time, &ifd->ifnow_);
-       }
-#else
-       if (TV_LT(nowp, &ifd->ifnow_)) {
-               TV_ADD_DELTA(&ifd->ifnow_, pkt_time, &ifd->ifnow_);
-       } else {
-               TV_ADD_DELTA(nowp, pkt_time, &ifd->ifnow_);
-       }
-#endif
-
-       while (cl != NULL) {
-               TV_DELTA(&ifd->ifnow_, &cl->last_, idle);
-               if (idle >= 2000000)
-                       /*
-                        * this class is idle enough, reset avgidle.
-                        * (TV_DELTA returns 2000000 us when delta is large.)
-                        */
-                       cl->avgidle_ = cl->maxidle_;
-
-               /* get pkt_time (for class) in usec */
-#if 1  /* use approximation */
-               pkt_time = pktlen * cl->ns_per_byte_;
-               pkt_time = NSEC_TO_USEC(pkt_time);
-#else
-               pkt_time = pktlen * cl->ns_per_byte_ / 1000;
-#endif
-               idle -= pkt_time;
-
-               avgidle = cl->avgidle_;
-               avgidle += idle - (avgidle >> RM_FILTER_GAIN);
-               cl->avgidle_ = avgidle;
-
-               /* Are we overlimit ? */
-               if (avgidle <= 0) {
-                       CBQTRACE(rmc_update_class_util, 'milo',
-                           cl->stats_.handle);
-                       /*
-                        * need some lower bound for avgidle, otherwise
-                        * a borrowing class gets unbounded penalty.
-                        */
-                       if (avgidle < cl->minidle_)
-                               avgidle = cl->avgidle_ = cl->minidle_;
-
-                       /* set next idle to make avgidle 0 */
-                       tidle = pkt_time +
-                           (((1 - RM_POWER) * avgidle) >> RM_FILTER_GAIN);
-                       TV_ADD_DELTA(nowp, tidle, &cl->undertime_);
-                       ++cl->stats_.over;
-               } else {
-                       cl->avgidle_ =
-                           (avgidle > cl->maxidle_) ? cl->maxidle_ : avgidle;
-                       cl->undertime_.tv_sec = 0;
-                       if (cl->sleeping_) {
-                               CALLOUT_STOP(&cl->callout_);
-                               cl->sleeping_ = 0;
-                       }
-               }
-
-               if (borrows != NULL) {
-                       if (borrows != cl)
-                               ++cl->stats_.borrows;
-                       else
-                               borrows = NULL;
-               }
-               cl->last_ = ifd->ifnow_;
-               cl->last_pkttime_ = pkt_time;
-
-#if 1
-               if (cl->parent_ == NULL) {
-                       /* take stats of root class */
-                       PKTCNTR_ADD(&cl->stats_.xmit_cnt, 1, pktlen);
-               }
-#endif
-
-               cl = cl->parent_;
-       }
-
-       /*
-        * Check to see if cutoff needs to set to a new level.
-        */
-       cl = ifd->class_[ifd->qo_];
-       if (borrowed && (ifd->cutoff_ >= borrowed->depth_)) {
-               if ((qlen(&cl->q_) <= 0) ||
-                   TV_LT(nowp, &borrowed->undertime_)) {
-                       rmc_tl_satisfied(ifd, nowp);
-                       CBQTRACE(rmc_update_class_util, 'broe', ifd->cutoff_);
-               } else {
-                       ifd->cutoff_ = borrowed->depth_;
-                       CBQTRACE(rmc_update_class_util, 'ffob',
-                           borrowed->depth_);
-               }
-       }
-
-       /*
-        * Release class slot
-        */
-       ifd->borrowed_[ifd->qo_] = NULL;
-       ifd->class_[ifd->qo_] = NULL;
-       ifd->qo_ = (ifd->qo_ + 1) % ifd->maxqueued_;
-       ifd->queued_--;
-}
-
-/*
- * void
- * rmc_drop_action(struct rm_class *cl) - Generic (not protocol-specific)
- *     over-limit action routines.  These get invoked by rmc_under_limit()
- *     if a class with packets to send if over its bandwidth limit & can't
- *     borrow from a parent class.
- *
- *     Returns: NONE
- */
-
-static void
-rmc_drop_action(struct rm_class *cl)
-{
-       struct rm_ifdat *ifd = cl->ifdat_;
-
-       VERIFY(qlen(&cl->q_) > 0);
-       IFCQ_CONVERT_LOCK(ifd->ifq_);
-       _rmc_dropq(cl);
-       if (qempty(&cl->q_))
-               ifd->na_[cl->pri_]--;
-}
-
-void
-rmc_drop(struct rm_class *cl, u_int32_t flow, u_int32_t *packets,
-    u_int32_t *bytes)
-{
-       struct rm_ifdat *ifd = cl->ifdat_;
-       struct ifclassq *ifq = ifd->ifq_;
-       u_int32_t pkt = 0, len = 0, qlen;
-
-       if ((qlen = qlen(&cl->q_)) != 0) {
-               IFCQ_CONVERT_LOCK(ifq);
-#if CLASSQ_RIO
-               if (q_is_rio(&cl->q_))
-                       rio_purgeq(cl->rio_, &cl->q_, flow, &pkt, &len);
-               else
-#endif /* CLASSQ_RIO */
-#if CLASSQ_RED
-               if (q_is_red(&cl->q_))
-                       red_purgeq(cl->red_, &cl->q_, flow, &pkt, &len);
-               else
-#endif /* CLASSQ_RED */
-#if CLASSQ_BLUE
-               if (q_is_blue(&cl->q_))
-                       blue_purgeq(cl->blue_, &cl->q_, flow, &pkt, &len);
-               else
-#endif /* CLASSQ_BLUE */
-               if (q_is_sfb(&cl->q_) && cl->sfb_ != NULL)
-                       sfb_purgeq(cl->sfb_, &cl->q_, flow, &pkt, &len);
-               else
-                       _flushq_flow(&cl->q_, flow, &pkt, &len);
-
-               if (pkt > 0) {
-                       VERIFY(qlen(&cl->q_) == (qlen - pkt));
-
-                       PKTCNTR_ADD(&cl->stats_.drop_cnt, pkt, len);
-                       IFCQ_DROP_ADD(ifq, pkt, len);
-
-                       VERIFY(((signed)IFCQ_LEN(ifq) - pkt) >= 0);
-                       IFCQ_LEN(ifq) -= pkt;
-
-                       if (qempty(&cl->q_))
-                               ifd->na_[cl->pri_]--;
-               }
-       }
-       if (packets != NULL)
-               *packets = pkt;
-       if (bytes != NULL)
-               *bytes = len;
-}
-
-void
-rmc_dropall(struct rm_class *cl)
-{
-       rmc_drop(cl, 0, NULL, NULL);
-}
-
-/*
- * void
- * rmc_delay_action(struct rm_class *cl) - This function is the generic CBQ
- *     delay action routine.  It is invoked via rmc_under_limit when the
- *     packet is discoverd to be overlimit.
- *
- *     If the delay action is result of borrow class being overlimit, then
- *     delay for the offtime of the borrowing class that is overlimit.
- *
- *     Returns: NONE
- */
-
-void
-rmc_delay_action(struct rm_class *cl, struct rm_class *borrow)
-{
-       int     ndelay, t, extradelay;
-
-       cl->stats_.overactions++;
-       TV_DELTA(&cl->undertime_, &cl->overtime_, ndelay);
-#ifndef BORROW_OFFTIME
-       ndelay += cl->offtime_;
-#endif
-
-       if (!cl->sleeping_) {
-               CBQTRACE(rmc_delay_action, 'yled', cl->stats_.handle);
-#ifdef BORROW_OFFTIME
-               if (borrow != NULL)
-                       extradelay = borrow->offtime_;
-               else
-#endif
-                       extradelay = cl->offtime_;
-
-               /*
-                * XXX recalculate suspend time:
-                * current undertime is (tidle + pkt_time) calculated
-                * from the last transmission.
-                *      tidle: time required to bring avgidle back to 0
-                *      pkt_time: target waiting time for this class
-                * we need to replace pkt_time by offtime
-                */
-               extradelay -= cl->last_pkttime_;
-               if (extradelay > 0) {
-                       TV_ADD_DELTA(&cl->undertime_, extradelay,
-                           &cl->undertime_);
-                       ndelay += extradelay;
-               }
-
-               cl->sleeping_ = 1;
-               cl->stats_.delays++;
-
-               /*
-                * Since packets are phased randomly with respect to the
-                * clock, 1 tick (the next clock tick) can be an arbitrarily
-                * short time so we have to wait for at least two ticks.
-                * NOTE:  If there's no other traffic, we need the timer as
-                * a 'backstop' to restart this class.
-                */
-               if (ndelay > tick * 2) {
-                       /*
-                        * FreeBSD rounds up the tick;
-                        * other BSDs round down the tick.
-                        */
-                       t = hzto(&cl->undertime_) + 1;
-               } else {
-                       t = 2;
-               }
-               CALLOUT_RESET(&cl->callout_, t,
-                   (timeout_t *)rmc_restart, (caddr_t)cl);
-       }
-}
-
-/*
- * void
- * rmc_restart() - is just a helper routine for rmc_delay_action -- it is
- *     called by the system timer code & is responsible checking if the
- *     class is still sleeping (it might have been restarted as a side
- *     effect of the queue scan on a packet arrival) and, if so, restarting
- *     output for the class.  Inspecting the class state & restarting output
- *     require locking the class structure.  In general the driver is
- *     responsible for locking but this is the only routine that is not
- *     called directly or indirectly from the interface driver so it has
- *     know about system locking conventions.
- *
- *     Returns:        NONE
- */
-
-static void
-rmc_restart(struct rm_class *cl)
-{
-       struct rm_ifdat *ifd = cl->ifdat_;
-
-       if (cl->sleeping_) {
-               cl->sleeping_ = 0;
-               cl->undertime_.tv_sec = 0;
-
-               if (ifd->queued_ < ifd->maxqueued_ && ifd->restart != NULL) {
-                       CBQTRACE(rmc_restart, 'trts', cl->stats_.handle);
-                       (ifd->restart)(ifd->ifq_);
-               }
-       }
-}
-
-/*
- * void
- * rmc_root_overlimit(struct rm_class *cl) - This the generic overlimit
- *     handling routine for the root class of the link sharing structure.
- *
- *     Returns: NONE
- */
-static void
-rmc_root_overlimit(struct rm_class *cl,
-    struct rm_class *borrow)
-{
-#pragma unused(cl, borrow)
-       panic("rmc_root_overlimit");
-}
-
-/*
- * Packet Queue handling routines.  Eventually, this is to localize the
- *     effects on the code whether queues are red queues or droptail
- *     queues.
- */
-
-static int
-_rmc_addq(rm_class_t *cl, struct mbuf *m, struct pf_mtag *t)
-{
-#if CLASSQ_RIO
-       if (q_is_rio(&cl->q_))
-               return (rio_addq(cl->rio_, &cl->q_, m, t));
-       else
-#endif /* CLASSQ_RIO */
-#if CLASSQ_RED
-       if (q_is_red(&cl->q_))
-               return (red_addq(cl->red_, &cl->q_, m, t));
-       else
-#endif /* CLASSQ_RED */
-#if CLASSQ_BLUE
-       if (q_is_blue(&cl->q_))
-               return (blue_addq(cl->blue_, &cl->q_, m, t));
-       else
-#endif /* CLASSQ_BLUE */
-       if (q_is_sfb(&cl->q_)) {
-               if (cl->sfb_ == NULL) {
-                       struct ifclassq *ifq = cl->ifdat_->ifq_;
-                       struct ifnet *ifp = ifq->ifcq_ifp;
-
-                       VERIFY(cl->flags_ & RMCF_LAZY);
-                       IFCQ_CONVERT_LOCK(ifq);
-
-                       cl->sfb_ = sfb_alloc(ifp, cl->stats_.handle,
-                           qlimit(&cl->q_), cl->qflags_);
-                       if (cl->sfb_ == NULL) {
-                               /* fall back to droptail */
-                               qtype(&cl->q_) = Q_DROPTAIL;
-                               cl->flags_ &= ~RMCF_SFB;
-                               cl->qflags_ &= ~(SFBF_ECN | SFBF_FLOWCTL);
-
-                               log(LOG_ERR, "%s: CBQ SFB lazy allocation "
-                                   "failed for qid=%d pri=%d, falling back "
-                                   "to DROPTAIL\n", if_name(ifp),
-                                   cl->stats_.handle, cl->pri_);
-                       }
-               }
-               if (cl->sfb_ != NULL)
-                       return (sfb_addq(cl->sfb_, &cl->q_, m, t));
-       }
-#if PF_ECN
-       else if (cl->flags_ & RMCF_CLEARDSCP)
-               write_dsfield(m, t, 0);
-#endif /* PF_ECN */
-
-       /* test for qlen > qlimit is done by caller */
-       _addq(&cl->q_, m);
-       return (0);
-}
-
-/* note: _rmc_dropq is not called for red */
-static void
-_rmc_dropq(rm_class_t *cl)
-{
-       struct mbuf *m;
-
-       if ((m = _rmc_getq(cl)) != NULL)
-               m_freem(m);
-}
-
-static struct mbuf *
-_rmc_getq(rm_class_t *cl)
-{
-#if CLASSQ_RIO
-       if (q_is_rio(&cl->q_))
-               return (rio_getq(cl->rio_, &cl->q_));
-       else
-#endif /* CLASSQ_RIO */
-#if CLASSQ_RED
-       if (q_is_red(&cl->q_))
-               return (red_getq(cl->red_, &cl->q_));
-       else
-#endif /* CLASSQ_RED */
-#if CLASSQ_BLUE
-       if (q_is_blue(&cl->q_))
-               return (blue_getq(cl->blue_, &cl->q_));
-       else
-#endif /* CLASSQ_BLUE */
-       if (q_is_sfb(&cl->q_) && cl->sfb_ != NULL)
-               return (sfb_getq(cl->sfb_, &cl->q_));
-
-       return (_getq(&cl->q_));
-}
-
-static struct mbuf *
-_rmc_pollq(rm_class_t *cl)
-{
-       return (qhead(&cl->q_));
-}
-
-void
-rmc_updateq(rm_class_t *cl, cqev_t ev)
-{
-#if CLASSQ_RIO
-       if (q_is_rio(&cl->q_))
-               return (rio_updateq(cl->rio_, ev));
-#endif /* CLASSQ_RIO */
-#if CLASSQ_RED
-       if (q_is_red(&cl->q_))
-               return (red_updateq(cl->red_, ev));
-#endif /* CLASSQ_RED */
-#if CLASSQ_BLUE
-       if (q_is_blue(&cl->q_))
-               return (blue_updateq(cl->blue_, ev));
-#endif /* CLASSQ_BLUE */
-       if (q_is_sfb(&cl->q_) && cl->sfb_ != NULL)
-               return (sfb_updateq(cl->sfb_, ev));
-}
-
-#ifdef CBQ_TRACE
-
-struct cbqtrace                 cbqtrace_buffer[NCBQTRACE+1];
-struct cbqtrace                *cbqtrace_ptr = NULL;
-int                     cbqtrace_count;
-
-/*
- * DDB hook to trace cbq events:
- *  the last 1024 events are held in a circular buffer.
- *  use "call cbqtrace_dump(N)" to display 20 events from Nth event.
- */
-void cbqtrace_dump(int);
-static char *rmc_funcname(void *);
-
-static struct rmc_funcs {
-       void    *func;
-       char    *name;
-} rmc_funcs[] =
-{
-       rmc_init,               "rmc_init",
-       rmc_queue_packet,       "rmc_queue_packet",
-       rmc_under_limit,        "rmc_under_limit",
-       rmc_update_class_util,  "rmc_update_class_util",
-       rmc_delay_action,       "rmc_delay_action",
-       rmc_restart,            "rmc_restart",
-       _rmc_wrr_dequeue_next,  "_rmc_wrr_dequeue_next",
-       NULL,                   NULL
-};
-
-static char *
-rmc_funcname(void *func)
-{
-       struct rmc_funcs *fp;
-
-       for (fp = rmc_funcs; fp->func != NULL; fp++)
-               if (fp->func == func)
-                       return (fp->name);
-       return ("unknown");
-}
-
-void
-cbqtrace_dump(int counter)
-{
-       int      i, *p;
-       char    *cp;
-
-       counter = counter % NCBQTRACE;
-       p = (int *)&cbqtrace_buffer[counter];
-
-       for (i = 0; i < 20; i++) {
-               log(LOG_DEBUG, "[0x%x] ", *p++);
-               log(LOG_DEBUG, "%s: ", rmc_funcname((void *)*p++));
-               cp = (char *)p++;
-               log(LOG_DEBUG, "%c%c%c%c: ", cp[0], cp[1], cp[2], cp[3]);
-               log(LOG_DEBUG, "%d\n", *p++);
-
-               if (p >= (int *)&cbqtrace_buffer[NCBQTRACE])
-                       p = (int *)cbqtrace_buffer;
-       }
-}
-#endif /* CBQ_TRACE */
-#endif /* PKTSCHED_CBQ */